【发布时间】:2021-06-17 17:06:57
【问题描述】:
这个问题背后的主题可能不是特定于 Blazor 中的导航链接,但它们是组件的一个示例,我可以在其中尝试一些东西而不会破坏我正在处理的所有应用程序。 当您在 blazor 中有导航链接时,您可以做的最快的事情是硬编码路径,例如:
<Navlink href="/products">Products</Navlink>
但是,如果您稍后必须添加一些内容,例如用户将在网站上更改的语言路径参数,该怎么办?此参数将在您的所有组件中通用。
因此,为了避免更改所有导航链接路径,您编写了一个函数,这样您只需要在一个地方更改代码,例如:
<Navlink href"@NavigateToProducts">Products</Navlink>
@code {
[Parameter]
public String Language {get; set;} // this comes from main layout page for example
private void NavigateToProducts()
{
NavigationManager.NavigateTo("$/{Language}/products");
}
}
你也可以像这样写一个更通用的,接受一个或多个参数:
<Navlink href="@NavigateTo("products")">Products</Navlink>
@code {
[Parameter]
public String Language {get; set;] // this comes from main layout page for example
private void NavigateTo(params String[] args)
{
var path = $"/{Language}"; // yeah could use a string builder
foreach(var arg in args)
path += $"/{arg}";
NavigationManager.NavigateTo($"{path}");
}
}
所以这一切都很好,但如果您有更多类别而不仅仅是产品,甚至只是其他组件,您需要复制并粘贴此功能,以便为您的导航链接导航。
我尝试做的是首先使用扩展方法创建一个静态类,以便:
<Navlink href="@(new String[]{"products"}.GetPath(Language))"
// In another file
public static class ExtensionMethods {
public static String GetPath(this String[] parameters, String language)
{
var path = $"/{language}";
foreach(var arg in args)
path += $"/{arg}";
return path;
}
}
但是我很快意识到这并没有解决任何问题,除了使代码更加臃肿,需要创建一个数组并调用方法之外,你并没有真正解决如果需要添加一些东西的问题,你有再次去编辑所有导航链接并添加第二个参数。
那么你还能做什么呢?您可以创建一个注入所有组件的服务:
@inject IUriService UriService
<Navlink href="@(UriService.GetPath("products"))">Products</Navlink>
//In another file
public class UriService : IUriService
{
private readonly StringBuilder _strBuilder;
private String _language;
public UriService(NavigationManager navigationManager)
{
_language = // use navigation manager to get the language from url or whatever
_strBuilder = new StringBuilder();
}
public String GetPath(params String[] pathParams)
{
if (pathParams == null)
throw new ArgumentNullException(nameof(pathParams));
_strBuilder.Clear();
_strBuilder.Append($"/{_language}");
foreach (var param in pathParams)
_strBuilder.Append($"/{param}");
return _strBuilder.ToString();
}
}
最后,如果我需要更改所有导航链接的通用内容,我只需要来这里! 这一切都有效,但是当用户更改语言时,我如何使用新语言更新我的服务? 我可以创建变量 _language 属性并将其设置在我需要的位置,在我的情况下是在导航栏组件中:
// The HTML code for the navbar//
// A dropdown menu where you can choose the language that on click will trigger OnLanguageChanged()
@code {
private void OnLanguageChanged()
{
// The logic for changing the language //
UriService.Language = "en";
}
}
或者为了更封装和更清楚你在做什么,我可以在 uri 服务中创建一个方法:
public void UpdateLanguage(String newLanguage)
{
_language = newLanguage;
}
不过,这看起来很混乱,如果您注入了 uri 服务,则可以随时更改变量。另外,该服务目前是瞬态的,应该是单例吗? 我不知道是否有使用事件的方法,但我无法想象可以从 uri 服务订阅导航栏组件的事件。或者是? 我知道这是一个很长的帖子,可能是一个微不足道的问题,但我对这些东西有点缺乏经验,在处理其他类似情况时记住它可能是一件好事。
【问题讨论】:
-
common across all of your components- 听起来您想不理会您的导航链接并在 cascading values 中传递该信息。 -
@GSerg 我想到了这一点,但是如果我需要添加参数,我仍然需要将 NavigateTo 函数复制到所有组件,然后使用新参数对其进行修改。也许没关系,我不是说不是,我只是说那是我需要做的。或者我可以级联一个参数数组并在其中添加新参数?
-
我的建议是为自己构建一个自定义的
NavLink组件,而不是NavLink- 你可以从这里提取代码 - github.com/dotnet/aspnetcore/blob/main/src/Components/Web/src/… - 然后或者从语言中获取你的语言您已注册的服务或级联值,但如果用户可以在 SPA 运行时更改它,该服务看起来是一个更好的选择。如果您喜欢这个想法,可以发布一些入门代码作为答案。 -
@ShaunCurtis 是的,用户可以在应用程序运行时更改语言。它是导航栏中的一个下拉菜单,它与 ofc 共享,并且始终可见(它写在主布局页面中),因此当用户更改语言时,从资源文件中应用所有翻译并且页面中的所有当前内容都重新渲染.是的,您可以继续发布答案,我真的很喜欢您的建议。我对您将如何构建语言服务感兴趣,其余的我可以自己归档并使用示例。
-
给我几个小时。我给你结构然后你可以填写细节。