第三章 组件(7)- 布局与Sections

embedded/2025/2/21 9:07:42/

布局

有些应用元素(例如菜单、版权消息和公司徽标)通常是应用整体布局的一部分。 如果在每一个组件中都编写这些应用元素,那每次更新其中一个应用元素时,都必须同时更新使用该元素的每个组件。 这种方法的维护成本很高,并且如果漏掉没有更新,还可能会导致内容不一致,显然是一种效率较低的方法。通过布局可以解决这些问题。

一、创建布局组件

Blazor的布局,本质上就是一个 Razor组件,它与引用它的组件共享标签。 和普通组件一样,布局组件可以使用数据绑定、依赖关系注入和组件的其他功能。

创建布局组件

布局组件像普通Razor组件一样使用 .razor 文件扩展名。 由于布局组件是在应用组件间共享的,因此它们通常放置在应用的 ShareLayout 文件夹中。

布局组件继承自LayoutComponentBaseLayoutComponentBase为布局内要渲染的主体内容定义子内容渲染片段 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. " +"https://www.doctorwho.tv/ https://www.bbc.com";
    }
    

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="https://www.bbc.co.uk/programmes/p00vfknq"><em>The Ribos Operation</em></a></li><li><a href="https://www.bbc.co.uk/programmes/p00vfdsb"><em>The Sunmakers</em></a></li><li><a href="https://www.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. " +"https://www.doctorwho.tv/ https://www.bbc.com";
    }
    

Sections

在.Net8引入了用于控制子组件内容的概念—Sections。Sections允许父组件从子组件中获取部分内容进行控制。Sections既可以在布局中使用,也可以在嵌套的父子组件中使用。

SectionOutletSectionContent组件

Sections需要通过SectionOutletSectionContent两个内置组件来实现:

  • SectionOutlet:渲染子组件中使用 SectionContent 组件所提供的内容,这些组件具有匹配的 SectionNameSectionId 参数。 两个或更多个 SectionOutlet 组件不能具有相同的 SectionNameSectionId
  • SectionContent:将组件中的指定内容作为 RenderFragment 提供给具有匹配的 SectionNameSectionIdSectionOutlet 组件。 如果多个 SectionContent 组件具有相同的 SectionNameSectionId,则匹配的 SectionOutlet 组件将渲染上一个渲染的 SectionContent 的内容。

试了一下,这里的上一个,指的是:如果是同一个组件中有多个SectionContent 那么将渲染在组件中从上到下的最后一个;如果兄弟组件中有多个SectionContent ,那么就按照组件之间的排序,渲染最后一个;如果是嵌套组件中有多个SectionContent ,则渲染辈分最小的那个组件中的SectionContent

SectionNameSectionId参数

两个组件中的参数SectionName接收字符串(建议用kebab方式,例如top-bar),SectionId则接收object字段(也就是C#变量,建议用Pascal方式起名)。

由于SectionName参数接收字符串作为设定值,如果要将这些字符串进行管理并不方便,因此更建议在代码中声明静态object对象。 然后,将object对象分配给ContentId参数

引用命名空间

SectionOutletSectionContent位于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="https://learn.microsoft.com/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引用了SectionIdMainLayout.ATargetSectionContent内容,只有导航到counter.razor组件后,布局组件才能将这个内容渲染出来。


http://www.ppmy.cn/embedded/164029.html

相关文章

vue前端项目,如何实现瀑布流布局

• 1. vue前端项目&#xff0c;如何实现瀑布流布局 • 1.1. 使用 CSS Grid 实现简单瀑布流• 1.2. 使用 vue-waterfall-easy 或其他专门插件• 1.3. 手动实现瀑布流逻辑 1. vue前端项目&#xff0c;如何实现瀑布流布局 在Vue前端项目中实现瀑布流布局&#xff0c;可以通过多种…

vue3项目上线配置 nginx代理

vue3项目上线配置 nginx代理 啥是Nginx代理 你可以把Nginx想象成一个小区的门卫大叔。小区里有好多户人家&#xff08;就像服务器上的不同服务&#xff09;&#xff0c;外面的人&#xff08;用户&#xff09;想要进来找某户人家&#xff08;访问某个服务&#xff09;&#xf…

4.从零开始学会Vue--{{组件通信}}

1.组件的注意点 1.template只能有一个根元素 约束&#xff1a;.vue文件中的template中如果写了两个元素&#xff0c;则会报如下错误 解决&#xff1a;保证template中只有一个根元素即可 2.scoped解决样式冲突 1全局样式: 默认组件中的样式会作用到全局&#xff0c;任何一个组…

Python 高级特性-切片

目录 切片 练习 小结 掌握了Python的数据类型、语句和函数&#xff0c;基本上就可以编写出很多有用的程序了。 比如构造一个1, 3, 5, 7, ..., 99的列表&#xff0c;可以通过循环实现&#xff1a; L [] n 1 while n < 99:L.append(n)n n 2 取list的前一半的元素&am…

pdf转换成word在线 简单好用 支持批量转换 效率高 100%还原

pdf转换成word在线 简单好用 支持批量转换 效率高 100%还原 在数字化办公的浪潮中&#xff0c;文档格式转换常常让人头疼不已&#xff0c;尤其是 PDF 转 Word 的需求极为常见。PDF 格式虽然方便阅读和传输&#xff0c;但难以编辑&#xff0c;而 Word 格式却能灵活地进行内容修…

Flask 发送邮件

下载 pip install flask-mail config.py MAIL_SERVER "smtp.qq.com" MAIL_USE_SSL True MAIL_PORT 465 MAIL_USERNAME "xxxxqq.com" MAIL_PASSWORD "xxxxx" MAIL_DEFAULT_SENDER "xxxxqq.com" 引入flask_mail exts.py fro…

LLM论文笔记 15: Transformers Can Achieve Length Generalization But Not Robustly

Arxiv日期&#xff1a;2024.2.14机构&#xff1a;Google DeepMind / University of Toronto 关键词 长度泛化位置编码数据格式 核心结论 1. 实验结论&#xff1a;十进制加法任务上的长度泛化最佳组合&#xff1a; FIRE位置编码 随机化位置编码 反向数据格式 索引提示&…

MySQL(1)基础篇

执行一条 select 语句&#xff0c;期间发生了什么&#xff1f; | 小林coding 目录 1、连接MySQL服务器 2、查询缓存 3、解析SQL语句 4、执行SQL语句 5、MySQL一行记录的存储结构 Server 层负责建立连接、分析和执行 SQL存储引擎层负责数据的存储和提取。支持InnoDB、MyIS…