第三章组件(7)-布局与Sections
- 人工智能
- 2025-08-24 10:18:02

布局
有些应用元素(例如菜单、版权消息和公司徽标)通常是应用整体布局的一部分。 如果在每一个组件中都编写这些应用元素,那每次更新其中一个应用元素时,都必须同时更新使用该元素的每个组件。 这种方法的维护成本很高,并且如果漏掉没有更新,还可能会导致内容不一致,显然是一种效率较低的方法。通过布局可以解决这些问题。
一、创建布局组件Blazor的布局,本质上就是一个 Razor组件,它与引用它的组件共享标签。 和普通组件一样,布局组件可以使用数据绑定、依赖关系注入和组件的其他功能。
创建布局组件
布局组件像普通Razor组件一样使用 .razor 文件扩展名。 由于布局组件是在应用组件间共享的,因此它们通常放置在应用的 Share 或 Layout 文件夹中。
布局组件继承自LayoutComponentBase,LayoutComponentBase为布局内要渲染的主体内容定义子内容渲染片段 Body 属性(也是RenderFragment,其作用跟ChildContent差不多的),因此在布局组件中,可以使用 @Body 指定主体内容的渲染位置。
示例-DoctorWhoLayout.razor
@inherits LayoutComponentBase <PageTitle>Doctor Who® Database</PageTitle> <header> <h1>Doctor Who® Database</h1> </header> <nav> <a href="main-list">Main Episode List</a> <a href="search">Search</a> <a href="new">Add Episode</a> </nav> @Body <footer> @TrademarkMessage </footer> @code { public string TrademarkMessage { get; set; } = "Doctor Who is a registered trademark of the BBC. " + " .doctorwho.tv/ .bbc "; }MainLayout组件
在从 Blazor 项目模板创建的应用中,MainLayout 组件就是应用的默认布局。 Blazor 的 CSS 隔离功能将独立 CSS 样式应用于 MainLayout组件。 按照约定,样式由相同名称的随附样式表 MainLayout.razor.css 提供。
二、设置布局组件的命名空间在引用布局组件时,如果没有指明布局的命名空间就找不到布局,Blazor提供了如下三种方式:
方式一
在 _Imports.razor 文件添加 @using 指令,用于指定布局组件的位置
...... @using BlazorServer.Components.Layout ......然后在使用布局的组件中用 @layout 指令使用布局组件。
方式二
在使用布局的组件顶部添加 @using 指令引入命名空间,并使用 @layout 指令使用具体的布局组件
@using BlazorSample.Components.Layout @layout DoctorWhoLayout方式三
在使用布局的组件中,通过完全命名空间和@layout指令使用布局组件
@layout BlazorSample.Components.Layout.DoctorWhoLayout 三、使用布局组件 1、向组件使用布局组件可以在单个组件中使用布局组件,直接通过@layout指令来使用布局组件就可以了,需要注意的是,使用布局组件的组件必须是具有@page 指令的可路由 Razor 组件。 编译器会将 @layout 转换为 [Layout],并将特性应用于所在的组件类。
Episodes.razor
@page "/episodes" @layout DoctorWhoLayout <h2>Doctor Who® Episodes</h2> <ul> <li> <a href=" .bbc.co.uk/programmes/p00vfknq"> <em>The Ribos Operation</em> </a> </li> <li> <a href=" .bbc.co.uk/programmes/p00vfdsb"> <em>The Sunmakers</em> </a> </li> <li> <a href=" .bbc.co.uk/programmes/p00vhc26"> <em>Nightmare of Eden</em> </a> </li> </ul>注意,在组件中直接使用布局组件会覆盖默认布局。
2、向组件文件夹应用布局Blazor项目中的每个文件夹都可以创建一个名为 _Imports.razor的文件。 编译器会将文件中所使用的指令应用到同一文件夹中(包括子文件夹)的所有Razor组件。 因此,包含 @layout DoctorWhoLayout 的 _Imports.razor 文件可确保文件夹中的所有组件都使用 DoctorWhoLayout组件,而无需将 @layout DoctorWhoLayout 重复的添加到文件夹和子文件夹内的所有Razor组件中。
注意
@layout指令只对具有 @page 指令的可路由 Razor 组件应用布局。在 _Imports.razor 中指定布局会覆盖默认布局。不要在根_Imports.razor文件(Components文件夹下的_Imports.razor文件)添加 @layout 指令,会造成无限循环布局,如果要使用全局布局,可以在Router组件中使用默认布局。 3、使用默认布局如果希望对全部组件都应用指定的布局组件,可以在 Router 组件的 RouteView 组件中使用 DefaultLayout 参数指定默认布局组件。
Router.razor
<Router AppAssembly="typeof(Program).Assembly"> <Found Context="routeData"> <RouteView RouteData="routeData" DefaultLayout="typeof(DoctorWhoLayout)" /> <FocusOnNavigate RouteData="routeData" Selector="h1" /> </Found> </Router>默认布局是使用布局组件的最通用且灵活的方法,建议使用。
4、在组件任意位置设置布局若要在任意的组件内设置布局,可以使用 LayoutView 组件指定布局。
Router.razor
<Router ...> <Found ...> ... </Found> <NotFound> <LayoutView Layout="typeof(ErrorLayout)"> <h1>Page not found</h1> <p>Sorry, there's nothing at this address.</p> </LayoutView> </NotFound> </Router> 四、嵌套布局组件可以引用一个布局,该布局又可以引用另一个布局。 例如,嵌套布局可用于创建多级菜单结构。
ProductionsLayout.razor
@inherits LayoutComponentBase <header> <h1>Productions</h1> </header> <nav> <a href="main-production-list">Main Production List</a> <a href="production-search">Search</a> <a href="new-production">Add Production</a> </nav> @Body <footer> Footer of Productions Layout </footer>DoctorWhoLayout.razor
@inherits LayoutComponentBase @layout ProductionsLayout <PageTitle>Doctor Who® Database</PageTitle> <h1>Doctor Who® Database</h1> <nav> <a href="main-episode-list">Main Episode List</a> <a href="episode-search">Search</a> <a href="new-episode">Add Episode</a> </nav> @Body <div> @TrademarkMessage </div> @code { public string TrademarkMessage { get; set; } = "Doctor Who is a registered trademark of the BBC. " + " .doctorwho.tv/ .bbc "; } Sections在.Net8引入了用于控制子组件内容的概念—Sections。Sections允许父组件从子组件中获取部分内容进行控制。Sections既可以在布局中使用,也可以在嵌套的父子组件中使用。
SectionOutlet和SectionContent组件
Sections需要通过SectionOutlet和SectionContent两个内置组件来实现:
SectionOutlet:渲染子组件中使用 SectionContent 组件所提供的内容,这些组件具有匹配的 SectionName 或 SectionId 参数。 两个或更多个 SectionOutlet 组件不能具有相同的 SectionName 或 SectionId。SectionContent:将组件中的指定内容作为 RenderFragment 提供给具有匹配的 SectionName 或 SectionId 的 SectionOutlet 组件。 如果多个 SectionContent 组件具有相同的 SectionName 或 SectionId,则匹配的 SectionOutlet 组件将渲染上一个渲染的 SectionContent 的内容。试了一下,这里的上一个,指的是:如果是同一个组件中有多个SectionContent 那么将渲染在组件中从上到下的最后一个;如果兄弟组件中有多个SectionContent ,那么就按照组件之间的排序,渲染最后一个;如果是嵌套组件中有多个SectionContent ,则渲染辈分最小的那个组件中的SectionContent 。
SectionName和SectionId参数
两个组件中的参数SectionName接收字符串(建议用kebab方式,例如top-bar),SectionId则接收object字段(也就是C#变量,建议用Pascal方式起名)。
由于SectionName参数接收字符串作为设定值,如果要将这些字符串进行管理并不方便,因此更建议在代码中声明静态object对象。 然后,将object对象分配给ContentId参数
引用命名空间
SectionOutlet和SectionContent位于ASP.NET Core的Sections命名空间中,因此在使用前,在_Imports.razor文件中进行引入。
@using Microsoft.AspNetCore.Components.Sections在布局中简单使用
这里以Blazor项目模板中的counter.razor组件为例,在里面添加一个部分。
counter.razor
@page "/counter" @rendermode InteractiveServer <PageTitle>Counter</PageTitle> <h1>Counter</h1> <p role="status">Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @* 这里添加一个部分组件内容 *@ <SectionContent SectionId="MainLayout.ATarget"> <a href="/">Go home</a> </SectionContent> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }MainLayout.razor
@inherits LayoutComponentBase <div class="page"> <div class="sidebar"> <NavMenu /> </div> <main> <div class="top-row px-4"> @* 这里引用子组件中的具有SectionName为a-target的SectionContent的内容 *@ <SectionOutlet SectionId="ATarget" /> <a href=" learn.microsoft /aspnet/core/" target="_blank">About</a> </div> <article class="content px-4"> @Body </article> </main> </div> <div id="blazor-error-ui"> An unhandled error has occurred. <a href="" class="reload">Reload</a> <a class="dismiss">🗙</a> </div> @code { public readonly static object ATarget = new object(); }上述例子中,在布局组件内使用SectionOutlet引用了SectionId为MainLayout.ATarget的SectionContent内容,只有导航到counter.razor组件后,布局组件才能将这个内容渲染出来。
第三章组件(7)-布局与Sections由讯客互联人工智能栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“第三章组件(7)-布局与Sections”