Blazor University 组件 — 级联值
Posted MyIO
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Blazor University 组件 — 级联值相关的知识,希望对你有一定的参考价值。
原文链接:https://blazor-university.com/components/cascading-values/
级联值
源代码[1]
我们已经看到 Blazor 如何允许我们使用参数[2]将上下文从父组件传递给子组件。随着组件变得越来越复杂,将其拆分为子组件的情况并不少见。在某些时候,一个组件可能会要求其使用者传递它自身不使用但它的一个子组件需要的状态。随着我们组件的结构随着时间的推移变得越来越复杂,我们可能会发现自己的组件需要添加多个参数,而这些参数并不被使用,而是简单地传递,因为它们在更深层次的某个地方需要。
以求职申请为例。一个 Vacancy
(空缺) 可以有很多 Applications
(申请);每份 Application
针对一个 Vacancy
,属于一个 Candidate
(候选人);Vacancy
和 Candidate
都有一个 Address
(地址)。
查看空缺显示所有申请。在某些时候,需要允许用户单击单个申请并在申请详情页面上详细查看它,因此创建了一个新的 ViewApplication.razor 组件,该组件将在查看空缺或查看单个申请时使用.
现在我们有一个 ViewVacancy.razor 组件(标记为 A),它遍历所有针对空缺的申请,并为每个申请呈现一个 ViewApplication.razor 组件(标记为 B)。
作为标准化应用程序的练习,决定应使用 ViewCandidate.razor 组件(标记为 C)显示候选人,并且应使用 ViewAddress.razor 组件(标记为 D)显示所有地址。
为了机会平等,显示空缺申请的页面需要在不透露候选人姓名或完整地址的情况下查看申请的选项,因此在“查看匿名数据”页面中添加了一个复选框。事实上,这个功能被认为对应用程序非常重要,复选框被添加到 MainLayout.razor 页面,因此它在整个系统的任何地方都可用。
ViewVacancy.razor 组件没有敏感数据,因此它不需要知道用户是否正在查看匿名数据。其中的 ViewApplication.razor 组件也没有敏感信息,所以它也不需要知道;但是 ViewCandidate.razor 组件需要匿名候选人的姓名,而 ViewCandidate.razor 组件中的 ViewAddress.razor 组件也需要匿名数据。
因为 ViewAddress.razor 和 ViewCandidate.razor 需要一个布尔参数来标识它们是否应该显示敏感信息,因此某些组件也必须需要相同的参数才能将其直接或间接传递给它托管的任何组件。
仅将数据传递给子级所需的参数的图示
这是用级联值解决的挑战。
按名称级联值
源代码[3]
指定级联参数的值非常简单。在我们的 Razor html 标记中的任何时候,我们都可以创建一个 CascadingValue
元素。该元素内呈现的所有内容都可以访问指定的值。
@page "/"
<h1>Toggle the options</h1>
<input @bind-value=FirstOptionValue type="checkbox" /> First option
<br />
<input @bind-value=SecondOptionValue type="checkbox" /> Second option
<br />
<CascadingValue Name="FirstOption" Value=@FirstOptionValue>
<CascadingValue Name="SecondOption" Value=@SecondOptionValue>
<FirstLevelComponent />
</CascadingValue>
</CascadingValue>
@code
bool FirstOptionValue;
bool SecondOptionValue;
使用级联值同样简单。任何组件,无论它在 CascadingValue
元素中的嵌套程度如何,都可以通过使用 CascadingParameter
属性修饰的属性来访问该值。
<ul>
<li>FirstOption = @FirstOption</li>
<li>SecondOption = @SecondOption</li>
</ul>
@code
[CascadingParameter(Name="FirstOption")]
private bool FirstOption get; set;
[CascadingParameter(Name="SecondOption")]
private bool SecondOption get; set;
请注意,我们使用该值的属性的名称是无关紧要的。Blazor 不会查找在 CascadingValue
元素中指定的同名属性;我们可以随意命名我们的属性,它实际上用的是 CascadingParameterAttribute
上的 Name
,它标识应该注入哪个级联值。
将充当级联参数的属性的可见性设置为私有是一种很好的做法。允许他们通过代码对使用者进行设置是不合逻辑的,因为该值实际上由设置 Cascading
值的父级所有。
按类型级联值
源代码[4]
之前我们看到了如何通过名称级联一个值。设置名称很重要,因为它用于通过匹配名称来将 CascadingValue
中指定的值推送到使用组件的正确属性中。另一种选择是在不指定名称的情况下指定 CascadingValue
,当 Blazor 遇到以这种方式指定的级联值时,如果属性满足以下条件,它会将其值注入到组件的属性中。
- 该属性使用
CascadingPropertyAttribute
进行装饰。 - [CascadingProperty] 没有指定名称。
- 该属性与 [CascadingValue] 中设置的类型相同(例如布尔值)。
- 该属性有一个设置器。
- 该属性是 public 的。
例如,以下 CascadingValue
将匹配 SomeComponent
中的两个 CascadingParameter
属性。
<CascadingValue Value=@true>
<SomeComponent/>
</CascadingValue>
Property1 = @Property1
Property2 = @Property2
@code
[CascadingParameter]
private bool Property1 get; set;
[CascadingParameter]
private bool Property2 get; set;
未命名的 CascadingValue
不如指定了 Name
的 CascadingValue
那样具体,因为每个具有正确类型且没有 Name
的 CascadingParameter
修饰属性都会使用该值。在我们定义一个简单的 .NET 类型(例如 bool
或 int
)的情况下,建议我们使用命名参数,但是,有时值的类型足以识别其用途;指定名称将是多余的,因此排除它可以节省一点时间。
随着求职申请的增长,我们最终可能会得到多个级联参数,例如:
-
bool ViewAnonymizedData
指示是否应隐藏个人身份信息。 -
string DateFormat
使用组件可以使用它以统一的方式格式化日期。 -
string LanguageCode
组件可以使用它来显示翻译后的文本。
这里出现的明显模式是这些都与用户的偏好有关。而不是使用带有多个 CascadingValue
元素的 Razor 标记,如下所示:
<CascadingValue Name="ViewAnonymizedData" Value=@ViewAnonymizedData>
<CascadingValue Name="DateFormat" Value=@DateFormat>
<CascadingValue Name="LanguageCode" Value=@LanguageCode>
(Body goes here)
</CascadingValue>
</CascadingValue>
</CascadingValue>
拥有一个自定义类会更有意义(并且需要更少的代码):
public class UserPreferences
public bool ViewAnonymizedData get; set;
public string DateFormat get; set;
public string LanguageCode get; set;
然后像这样创建你的 Razor 标记:
<CascadingValue Value=@UserPreferences>
</CascadingValue>
然后,使用组件只需要一个标记为 [CascadingParameter]
的属性,而不是三个。
@if (!UserPreferences.ViewAnonymizedData)
<div>
<span>Name</span> @Candidate.Name
</div>
<div>
<span>Date of birth</span> @Candidate.DateOfBirth.ToString(UserPreferences.DateFormat)
</div>
<ViewAddress Address=@Candidate.Address/>
else
<span>[Anonmymized view]</span>
@code
[CascadingParameter]
private UserPreferences UserPreferences get; set;
当然,这个例子忽略了如何根据 UserPreferences.LanguageCode
翻译静态文本。
重写级联值
级联值和级联参数允许它们的值向下级联渲染树,而无需从父级显式传递到子级。Blazor 的另一个特性是它允许我们在渲染树的下方重写 CascadingValue
的值。
给定以下 ViewSomeValue
组件,该组件显示名为 ValueToOverride
的 CascadingValue
的值:
<div>Values are @SomeValue1 / @SomeValue2</div>
@code
[CascadingParameter(Name = "CascadedValue")]
private string SomeValue1 get; set;
[CascadingParameter(Name = "ValueToOverride")]
private string SomeValue2 get; set;
以及使用该组件的以下页面:
@page "/overridden"
<CascadingValue Name="CascadedValue" Value=@CascadedValue>
<CascadingValue Name="ValueToOverride" Value=@OuterValue>
<h2>First level</h2>
<ViewSomeValue />
<CascadingValue Name="ValueToOverride" Value=@InnerValue>
<h2>Second level</h2>
<ViewSomeValue />
</CascadingValue>
<h2>Back to first level</h2>
<ViewSomeValue />
</CascadingValue>
</CascadingValue>
@code
string CascadedValue = "CascadedValue";
string OuterValue = "Outer value";
string InnerValue = "Inner value";
我们看到以下输出:
请注意第三个组件的 ValueToOverride
值如何自动恢复为“Outer value”。这是因为该值是由元素的深度决定的。第三个组件在最外面的 CascadingValue
中呈现,因此它是它找到的最近的包含匹配值的父级。
还要注意 CascadedValue
的值如何可用于所有组件。
参考资料
[1]
源代码: https://github.com/mrpmorris/blazor-university/tree/master/src/CascadingValues/ManualParameterPassing
[3]
源代码: https://github.com/mrpmorris/blazor-university/tree/master/src/CascadingValues/CascadingValuesByName
[4]
源代码: https://github.com/mrpmorris/blazor-university/tree/master/src/CascadingValues/CascadingValuesByType
以上是关于Blazor University 组件 — 级联值的主要内容,如果未能解决你的问题,请参考以下文章
Blazor University (11)组件 — 替换子组件的属性
Blazor University (12)组件 — 组件生命周期