当我来到我的 blazor 服务器端应用程序时,我感到奇怪的闪烁。
为了更好的用户体验,我实现了一个 GIF 悸动器,但之后加载并不流畅,正如您自己看到的那样:
https://shop6.gastroblitz.de/streetchooser
我的目标是在加载悸动完成后,页面应该完全显示并在一次刷新中:
性能问题的一些想法(但没有以我目前的知识改进的想法......
-
_Host.cshtml
-
在区域中预呈现"HtmlHeadComponent"(用于生成特定于域的标题,元数据等(
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <base href="~/" /> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <link rel="stylesheet" href="/css/main.css" /> <link rel="stylesheet" href="https://owlcarousel2.github.io/OwlCarousel2/assets/owlcarousel/assets/owl.carousel.min.css" /> <link rel="stylesheet" href="https://owlcarousel2.github.io/OwlCarousel2/assets/owlcarousel/assets/owl.theme.default.min.css" /> <script src="_content/Microsoft.AspNetCore.ProtectedBrowserStorage/protectedBrowserStorage.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <script src="/js/animations.js"></script> <script src="/js/simplebar.min.js"></script> <script src="/js/articlePopup.js"></script> <script src="/js/accordion.min.js"></script> <script src="https://owlcarousel2.github.io/OwlCarousel2/assets/owlcarousel/owl.carousel.js"> </script> <script src="/js/my.js"></script> <script src="_content/Blazor-Analytics/blazor-analytics.js"></script> @(await Html.RenderComponentAsync<HtmlHeadComponent>(RenderMode.ServerPrerendered)) </head> <body> <app> @(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered)) </app> <script src="_framework/blazor.server.js"></script> <script> Blazor.defaultReconnectionHandler._reconnectCallback = function (d) { document.location.reload(); } </script> <script src="https://cdn.syncfusion.com/ej2/17.4.43/dist/ej2.min.js"></script> <script src="https://cdn.syncfusion.com/ej2/17.4.43/dist/ejs.interop.min.js"></script> </body> </html>
-
-
App.razor
-
在这里,我只是从加载每个数据时开始(请参阅 if 语句 + 许多级联参数来处理子组件中的数据更改(
<Router AppAssembly="@typeof(Program).Assembly"> <Found Context="routeData"> @if (AppState.StoreData != null && AppState.MultiStoreData != null && AppState.StoreChooserData != null) { <CascadingValue Value="AppState.StoreData" Name="StoreData"> <CascadingValue Value="AppState.MultiStoreData" Name="MultiStoreData"> <CascadingValue Value="AppState.StoreChooserData" Name="StoreChooserData"> <CascadingValue Value="AppState.BasketData" Name="BasketData"> <CascadingValue Value="AppState.CheckoutData" Name="CheckoutData"> <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> <GoogleAnalytics TrackingId="@AppState.StoreData?.StoreContainer?.Store?.GoogleAnalyticsId" /> </CascadingValue> </CascadingValue> </CascadingValue> </CascadingValue> </CascadingValue> } else { <img class="center" src="/img-dev/ajax-loader.gif" /> } </Found> <NotFound> <LayoutView Layout="@typeof(MainLayout)"> <p>Sorry, there's nothing at this address.</p> </LayoutView> </NotFound>
-
-
最后一步是给定的storechooser页面,该页面也仅在所有数据可用时加载内容
@page "/streetchooser" @inherits StreetChooserBase @if (StoreChooserData != null && MultiStoreData != null) { <div class="slider" id="home"> <div id="owl-demo" class="owl-carousel owl-theme pitch_img"> @if (!string.IsNullOrEmpty(MultiStoreData.MultiStore.StreetChooserImage1)) { <div class="item"> <img src="img/@StoreData?.StoreContainer?.Store?.Key/@MultiStoreData.MultiStore.StreetChooserImage1" alt="" class="pitch_img" /> </div> } @if (!string.IsNullOrEmpty(MultiStoreData.MultiStore.StreetChooserImage2)) { <div class="item"> <img src="img/@StoreData?.StoreContainer?.Store?.Key/@MultiStoreData.MultiStore.StreetChooserImage2" alt="" class="pitch_img" /> </div> } @if (!string.IsNullOrEmpty(MultiStoreData.MultiStore.StreetChooserImage3)) { <div class="item"> <img src="img/@StoreData?.StoreContainer?.Store?.Key/@MultiStoreData.MultiStore.StreetChooserImage3" alt="" class="pitch_img" /> </div> } @if (!string.IsNullOrEmpty(MultiStoreData.MultiStore.StreetChooserImage4)) { <div class="item"> <img src="img/@StoreData?.StoreContainer?.Store?.Key/@MultiStoreData.MultiStore.StreetChooserImage4" alt="" class="pitch_img" /> </div> } @if (!string.IsNullOrEmpty(MultiStoreData.MultiStore.StreetChooserImage5)) { <div class="item"> <img src="img/@StoreData?.StoreContainer?.Store?.Key/@MultiStoreData.MultiStore.StreetChooserImage5" alt="" class="pitch_img" /> </div> } </div> <div class="slider_content "> <div class="container"> <div class="row "> <div class="col-sm-5"> @if (StoreChooserData != null && MultiStoreData != null) { <EditForm Model="@StoreChooserData"> <div class="search-section"> <div class="search-logo"> <img src="img/@StoreData?.StoreContainer?.Store?.Key/@StoreData?.StoreContainer?.Store?.LogoUrl" alt="" /> </div> <p>Sushi und mehr online bestellen und abholen oder direkt nach Hause liefern lassen.</p> <div class="row"> <div class="col-sm-6"> <div class="select-location @(StoreChooserData.OrderType == "1" ? "active" : "")" @onclick="OrderTypeChangedToDelivery"> Lieferung</div> </div> <div class="col-sm-6"> <div class="select-location @(StoreChooserData.OrderType == "2" ? "active" : "")" @onclick="OrderTypeChangedToPickup"> Selbstabholer</div> </div> </div> <div class="search-rest"> <label>Plz / Ort </label> <EjsComboBox Value="@StoreChooserData.PostcodeCitySite" ModelType="@typeof(Db_DeliveryStreet)" Placeholder="Ort eingeben" ShowClearButton="true" AllowCustom="true" AllowFiltering="true" FilterType="FilterType.Contains" NoRecordsTemplate="<div>Keine Ergebnisse</div>" DataSource="@MultiStoreData.DeliveryZones"> <AutoCompleteEvents TValue="string" ValueChange="PostcodeCityChanged"></AutoCompleteEvents> <ComboBoxFieldSettings GroupBy="Postcode" Value="FullName"></ComboBoxFieldSettings> <ComboBoxTemplates> <GroupTemplate Context="Item"> <span class="group">@((Item as Db_DeliveryStreet).Postcode)</span> </GroupTemplate> <ItemTemplate Context="Item"> <span><span class='name'>@((Item as Db_DeliveryStreet).CitySite)</span><span class='minOrderValue'>@($"ab {(Item as Db_DeliveryStreet).MinOrderValue?.ToString("f2")}€")</span></span> </ItemTemplate> </ComboBoxTemplates> </EjsComboBox> <ValidationMessage For="@(() => StoreChooserData.PostcodeCitySite)"> </ValidationMessage> </div> <div class="search-rest"> <label>Straße / Hausnr. </label> <EjsComboBox Value="@StoreChooserData.Street" ModelType="@typeof(StreetItem)" Placeholder="Straße eingeben" ShowClearButton="true" AllowCustom="true" AllowFiltering="true" FilterType="FilterType.Contains" NoRecordsTemplate="<div>Keine Ergebnisse</div>" DataSource="@Streets"> <AutoCompleteEvents TValue="string" ValueChange="StreetChanged"></AutoCompleteEvents> <ComboBoxFieldSettings Value="Name"></ComboBoxFieldSettings> </EjsComboBox> <ValidationMessage For="@(() => StoreChooserData.Street)"></ValidationMessage> </div> <div class="search-rest"> <button class="search-send-btn" @onclick="@GoToNext">weiter </button> </div> </div> </EditForm> } </div> </div> </div> </div> </div> <FooterComponent /> }
认为一个问题是图像在我的代码中很晚才被请求并产生闪烁......
但是,如何才能以更好的方式处理这个问题呢?或者也许另一点可能是一些问题。
希望你明白我的意思。
提前感谢!
我正在使用MemoryCache
来防止因使用RenderMode.ServerPrerendered
引起的闪烁。此问题在此线程中讨论。
通过在服务器上的预呈现和呈现阶段之间缓存结果集,可以避免过滤问题。希望他们在下一个版本中以某种方式修复它。
在服务器端 blazyor 上使用内存更简单、更好 为此缓存。
- 它避免了国家绊倒。
- 它可以与 react/redux 方法结合使用,您只需传递存储的 id 并将存储放入内存缓存中,其中包含 id,然后用于在应用重新连接时检索应用商店 并生成与预渲染相同的渲染。
下面的一个例子是修改后的天气服务,它显示它 不会导致闪烁。
public WeatherForecastService(IMemoryCache memoryCache) { MemoryCache = memoryCache; } public IMemoryCache MemoryCache { get; } public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate) { return MemoryCache.GetOrCreateAsync(startDate, async e => { e.SetOptions(new MemoryCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(30) }); var rng = new Random(); await Task.Delay(TimeSpan.FromSeconds(10)); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = startDate.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }).ToArray(); }); } private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
线路await Task.Delay(TimeSpan.FromSeconds(10));
仅用于演示目的,当然没有必要等待 10 秒。