刚刚使用 DevExpress 的免费 Blazor 代码<HEAD>
在运行时实现自定义数据:
_Hosts.cshtml(参见元素中的代码片段):
<!DOCTYPE html>
<html lang="en">
<head>
@(await Html.RenderComponentAsync<DocumentMetadataComponent>(RenderMode.ServerPrerendered))
</head>
<body>
<app>
@(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
</app>
<script src="_framework/blazor.server.js"></script>
</body>
Run Code Online (Sandbox Code Playgroud)
到目前为止效果很好(可以使标题、描述等动态化)。
现在的问题是我必须在顶层设置一些变量来过度使用和解释一次。我想知道使用的 url 并动态提供一些数据。
但以我现在的知识,我只能在每个组件(DocumentMetadataComponent + App)中做两次。
我在 MainLayout.razor 中获取数据:
<CascadingValue Value="StoreData" Name="StoreData">
@Body
</CascadingValue>
@code{
public StoreCompleteDTO StoreData { get; set; }
protected override async Task OnInitializedAsync()
{
using var tl = new TimeLogger($"MainLayout.razor OnInitializedAsync()");
StoreData = await AppState.GetStoreData(My.StoreId);
}
}
Run Code Online (Sandbox Code Playgroud)
这个 StoreData 变量必须在动态元数据中可用,因为我必须为其他商店选择不同的 CSS 文件...
希望解释清楚。
目标是只调用一次: StoreData = await AppState.GetStoreData(My.StoreId);
因为它是网络服务调用并且需要花费时间......
谢谢!
I would suggest the best way to make some information available across a Blazor application is to use the service system and Dependency Injection.
This means you can control the scope of the data (global? session?) as well as make it available on any page/component you need. Writing in the form of State container will also help in usage. Here is a quick sample that just sets the page title, but you can extend it to cover <meta>
for example.
/// <summary>
/// A state container for head tags
/// </summary>
public class HeadState
{
/// <summary>
/// Page title
/// </summary>
public string Title => _title;
// internal store
private string _title = "";
/// <summary>
/// Set the page title
/// </summary>
/// <param name="title"></param>
public void SetTitle(string title)
{
if(!string.Equals(_title,title))
{
_title = title;
HeadChanged?.Invoke();
}
}
/// <summary>
/// Event raised when data changes
/// </summary>
public event Action HeadChanged;
}
Run Code Online (Sandbox Code Playgroud)
The HeadState
class is a state container to allow us to set the page title. The title property is read-only so it has to be set via SetTitle, which triggers the HeadChanged
event so consumers know it's amended. We need to register this as a scoped service in Startup.cs
:
// declare the HeadState for DI
services.AddScoped<State.HeadState>();
Run Code Online (Sandbox Code Playgroud)
To implement it, we amend the _host.cshtml
to add a component that renders it in the <head>
section as per your question:
<head>
@(await Html.RenderComponentAsync<HeadComponent>(RenderMode.Server))
</head>
Run Code Online (Sandbox Code Playgroud)
The HeadComponent
injects the state and handles the render and updates:
@inject State.HeadState head
<title>@head.Title</title>
@code
{
// although the title is set on loading, if it is changed by a component we
// need to call StateHasChanged to trigger Blazor to rerender since the event
// that triggered it is outside this component
protected override void OnInitialized()
{
head.HeadChanged += () =>
{
StateHasChanged();
};
}
}
Run Code Online (Sandbox Code Playgroud)
To test it on a page (or any other component!) we just inject the state object and use it
@page "/"
@inject State.HeadState head
<h1>Head Demo</h1>
<button @onclick='(()=> head.SetTitle("Hello"))'>Set title to Hello</button>
<button @onclick='(()=> head.SetTitle("World"))'>Set title to World</button>
Run Code Online (Sandbox Code Playgroud)
Here we are just doing a <title>
tag for demo purposes but of course you can add <meta>
or other values. I'd avoid amending CSS stylesheets though as that possibly should be done via JS but I'm not 100% sure that's correct.
归档时间: |
|
查看次数: |
2279 次 |
最近记录: |