使用 Razor 类库 (RCL) 中的 ASP.NET Core Razor 组件
注意
此版本不是本文的最新版本。 对于当前版本,请参阅此文的 .NET 8 版本。
警告
此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 对于当前版本,请参阅此文的 .NET 8 版本。
组件可在 Razor 类库 (RCL) 中跨项目共享。 在应用中包含组件和静态资产,它们来自:
- 解决方案中的另一个项目。
- 引用的 .NET 库。
- NuGet 程序包。
正如组件是常规的 .NET 类型一样,RCL 提供的组件也是普通的 .NET 程序集。
创建 RCL
- 创建新项目。
- 在“新建项目”对话框中,从 ASP.NET Core 项目模板列表中选择“Razor 类库” 。 选择下一步。
- 在“配置新的项目”对话框的“项目名称”字段中提供项目名称。 本主题中的示例使用项目名称
ComponentLibrary
。 选择下一步。 - 在“其他信息”对话框中,请勿选择“支持页面和视图”。 选择创建。
- 将 RCL 添加到一个解决方案:
- 打开解决方案。
- 在解决方案资源管理器中,右击解决方案。 选择“添加”>“现有项目” 。
- 导航到 RCL 的项目文件。
- 选择 RCL 的项目文件 (
.csproj
)。
- 从应用中添加对 RCL 的引用:
- 右键单击该应用项目。 选择“添加”>“项目引用”。
- 选择 RCL 项目。 选择“确定”。
使用 RCL 中的 Razor 组件
若要在其他项目中使用 RCL 中的组件,则使用以下方法之一:
- 使用包含 RCL 命名空间的完整组件类型名称。
- 如果 Razor 的
@using
指令声明了 RCL 的命名空间,则可以使用不含 RCL 命名空间的名称添加各个组件。 使用以下方法:- 将
@using
指令添加到各个组件。 - 在顶级
_Imports.razor
文件中包含@using
指令,使库的组件可用于整个项目。 将指令添加到任何级别的_Imports.razor
文件,将命名空间应用于文件夹中的单个组件或一组组件。 使用_Imports.razor
文件时,各个组件不需要包含表示 RCL 命名空间的@using
指令。
- 将
在下面的示例中,ComponentLibrary
是包含 Component1
组件的 RCL。 如果从 RCL 项目模板创建的是不支持页面和视图 RCL,则示例组件 Component1
组件会自动添加到其中。
ComponentLibrary
RCL 中的 Component1.razor
:
<div class="my-component">
This component is defined in the <strong>ComponentLibrary</strong> package.
</div>
在使用 RCL 的应用中,使用其命名空间引用 Component1
组件,如下面的示例所示。
ConsumeComponent1.razor
:
@page "/consume-component-1"
<h1>Consume component (full namespace example)</h1>
<ComponentLibrary.Component1 />
或者,不使用其命名空间,而是添加一个 @using
指令以使用该组件。 以下 @using
指令还可以出现在当前文件夹中或其上方的任何 _Imports.razor
文件中。
ConsumeComponent2.razor
:
@page "/consume-component-2"
@using ComponentLibrary
<h1>Consume component (<code>@@using</code> example)</h1>
<Component1 />
如果库组件使用 CSS 隔离,组件样式会自动用于使用库的应用。 无需在使用该库的应用中手动链接或导入库的各个组件样式表或其捆绑的 CSS 文件。 应用使用 CSS 导入来引用 RCL 的捆绑样式。 捆绑样式不会作为使用该库的应用的静态 Web 资产发布。 对于名为 ClassLib
的类库和具有 BlazorSample.styles.css
样式表的 Blazor 应用,RCL 的样式表会在生成时自动导入到应用样式表的顶部:
@import '_content/ClassLib/ClassLib.bundle.scp.css';
在前面的示例中,Component1
的样式表 (Component1.razor.css
) 会自动捆绑。
ComponentLibrary
RCL 中的 Component1.razor.css
:
.my-component {
border: 2px dashed red;
padding: 1em;
margin: 1em 0;
background-image: url('background.png');
}
还会包含 RCL 项目模板中的背景图像,并将其保留在 RCL 的 wwwroot
文件夹中。
ComponentLibrary
RCL 中的 wwwroot/background.png
:
若要在库的 wwwroot
文件夹中的样式表中提供更多库组件样式,请向 RCL 的使用者添加样式表 <link>
标记,如下一个示例所示。
重要
通常,库组件使用 CSS 隔离来捆绑和提供组件样式。 依赖于 CSS 隔离的组件样式会自动提供给使用 RCL 的应用。 无需在使用该库的应用中手动链接或导入库的各个组件样式表或其捆绑的 CSS 文件。 以下示例在不使用 CSS 隔离的情况下提供全局样式表,这通常不是使用 RCL 的典型应用的要求。
下一个示例中使用了以下背景图像。 实现此部分中所示的示例后,请右键单击该图像以将其保存在本地。
ComponentLibrary
RCL 中的 wwwroot/extra-background.png
:
使用 extra-style
类向 RCL 添加新的样式表。
ComponentLibrary
RCL 中的 wwwroot/additionalStyles.css
:
.extra-style {
border: 2px dashed blue;
padding: 1em;
margin: 1em 0;
background-image: url('extra-background.png');
}
将组件添加到使用 extra-style
类的 RCL。
ComponentLibrary
RCL 中的 ExtraStyles.razor
:
<div class="extra-style">
<p>
This component is defined in the <strong>ComponentLibrary</strong> package.
</p>
</div>
在使用 RCL 的 ExtraStyles
组件的应用中添加一个页面。
ConsumeComponent3.razor
:
@page "/consume-component-3"
@using ComponentLibrary
<h1>Consume component (<code>additionalStyles.css</code> example)</h1>
<ExtraStyles />
在应用程序的 <head>
标记中链接到库的样式表(<head>
内容的位置):
Blazor Web App:
<link href="@Assets["_content/ComponentLibrary/additionalStyles.css"]" rel="stylesheet">
独立 Blazor WebAssembly 应用:
<link href="_content/ComponentLibrary/additionalStyles.css" rel="stylesheet">
<link href="_content/ComponentLibrary/additionalStyles.css" rel="stylesheet">
如果库组件使用 CSS 隔离,组件样式会自动用于使用库的应用。 无需在使用该库的应用中手动链接或导入库的各个组件样式表或其捆绑的 CSS 文件。 应用使用 CSS 导入来引用 RCL 的捆绑样式。 捆绑样式不会作为使用该库的应用的静态 Web 资产发布。 对于名为 ClassLib
的类库和具有 BlazorSample.styles.css
样式表的 Blazor 应用,RCL 的样式表会在生成时自动导入到应用样式表的顶部:
@import '_content/ClassLib/ClassLib.bundle.scp.css';
在前面的示例中,Component1
的样式表 (Component1.razor.css
) 会自动捆绑。
ComponentLibrary
RCL 中的 Component1.razor.css
:
.my-component {
border: 2px dashed red;
padding: 1em;
margin: 1em 0;
background-image: url('background.png');
}
还会包含 RCL 项目模板中的背景图像,并将其保留在 RCL 的 wwwroot
文件夹中。
ComponentLibrary
RCL 中的 wwwroot/background.png
:
RCL 的示例组件 Component1
使用以下背景图像和样式表。 无需将这些静态资产添加到从 RCL 项目模板创建的新 RCL,因为项目模板会自动添加它们。
ComponentLibrary
RCL 中的 wwwroot/background.png
:
ComponentLibrary
RCL 中的 wwwroot/styles.css
:
.my-component {
border: 2px dashed red;
padding: 1em;
margin: 1em 0;
background-image: url('background.png');
}
若要提供 Component1
的 my-component
CSS 类,请在应用的 <head>
标记(<head>
内容的位置)中链接到库的样式表。
<link href="_content/ComponentLibrary/styles.css" rel="stylesheet" />
使可路由组件可从 RCL 获取
若要使 RCL 中的可路由组件可用于直接请求,必须向应用的路由器公开 RCL 的程序集。
打开应用的 App
组件 (App.razor
)。 将 Assembly 集合分配给 Router 组件的 AdditionalAssemblies 参数以包括 RCL 的程序集。 在以下示例中,ComponentLibrary.Component1
组件用于发现 RCL 的程序集。
AdditionalAssemblies="new[] { typeof(ComponentLibrary.Component1).Assembly }"
有关详细信息,请参阅 ASP.NET Core Blazor 路由和导航。
在 wwwroot
文件夹中创建具有静态资产的 RCL
RCL 的静态资产可用于任何使用该库的应用。
将静态资产放在 RCL 的 wwwroot
文件夹中,并在应用中使用以下路径引用静态资产:_content/{PACKAGE ID}/{PATH AND FILE NAME}
。 {PACKAGE ID}
占位符是库的包 ID。 如果项目文件中没有指定 <PackageId>
,则包 ID 默认为项目的程序集名称。 {PATH AND FILE NAME}
占位符是 wwwroot
下的路径和文件名。 此路径格式还用于应用中由添加到 RCL 的 NuGet 包提供的静态资产。
下面的示例演示了如何使用名为 ComponentLibrary
的 RCL 和使用该 RCL 的 Blazor 应用使用 RCL 静态资产。 此应用包含对 ComponentLibrary
RCL 的项目引用。
本部分的示例中使用了下面的 Jeep® 图像。 实现此部分中所示的示例后,请右键单击该图像以将其保存在本地。
ComponentLibrary
RCL 中的 wwwroot/jeep-yj.png
:
在 RCL 中添加以下 JeepYJ
组件。
ComponentLibrary
RCL 中的 JeepYJ.razor
:
<h3>ComponentLibrary.JeepYJ</h3>
<p>
<img alt="Jeep YJ®" src="_content/ComponentLibrary/jeep-yj.png" />
</p>
在使用 ComponentLibrary
RCL 的应用中添加以下 Jeep
组件。 Jeep
组件使用:
ComponentLibrary
RCL 的wwwroot
文件夹中的 Jeep YJ® 图像。- RCL 中的
JeepYJ
组件。
Jeep.razor
:
@page "/jeep"
@using ComponentLibrary
<div style="float:left;margin-right:10px">
<h3>Direct use</h3>
<p>
<img alt="Jeep YJ®" src="_content/ComponentLibrary/jeep-yj.png" />
</p>
</div>
<JeepYJ />
<p>
<em>Jeep</em> and <em>Jeep YJ</em> are registered trademarks of
<a href="https://www.stellantis.com">FCA US LLC (Stellantis NV)</a>.
</p>
呈现的 Jeep
组件:
有关详细信息,请参阅使用 ASP.NET Core 的类库中的可重用 Razor UI。
使用与组件并置的 JavaScript 文件创建 RCL
为 Razor 组件并置 JavaScript (JS) 文件是整理应用中脚本的简便方法。
Blazor 应用的 Razor 组件使用 .razor.js
扩展名并置 JS 文件,并且可通过项目中文件的路径公开寻址:
{PATH}/{COMPONENT}.razor.js
- 占位符
{PATH}
是指向组件的路径。 - 占位符
{COMPONENT}
是组件。
发布应用后,框架会自动将脚本移动到 Web 根目录。 脚本将移动到 bin/Release/{TARGET FRAMEWORK MONIKER}/publish/wwwroot/{PATH}/{COMPONENT}.razor.js
,其中占位符为:
- 目标框架名字对象 (TFM) 为
{TARGET FRAMEWORK MONIKER}
。 {PATH}
是组件的路径。{COMPONENT}
是组件名称。
无需更改脚本的相对 URL,因为 Blazor 会为你将文件 JS 放置在已发布的静态资产中。
本部分和以下示例主要侧重于说明 JS 文件并置。 第一个示例演示了具有普通 JS 函数的 JS 并置文件。 第二个示例演示了如何使用模块加载函数,这是建议用于大多数生产应用的方法。 ASP.NET Core 中从 .NET 调用 JavaScript 函数的方法Blazor中全面介绍了从 .NET 调用 JS,其中还详细介绍了 BlazorJS API 并提供了一些额外示例。 ASP.NET Core Razor 组件生命周期中介绍了第二个示例中出现的组件处置。
以下 JsCollocation1
组件通过 HeadContent
组件加载脚本,并使用 IJSRuntime.InvokeAsync 调用函数 JS。 占位符 {PATH}
是指向组件的路径。
重要
如果在测试应用中使用以下代码进行演示,请将 {PATH}
占位符更改为组件的路径(例如:在 .NET 8 或更高版本中为 Components/Pages
,在 .NET 7 或更低版本中为 Pages
)。 在 Blazor Web App(.NET 8 或更高版本)中,组件需要全局应用到应用程序或组件定义的交互式呈现模式。
在脚本 Blazor 后添加以下脚本(启动脚本 Blazor 的位置):
<script src="{PATH}/JsCollocation1.razor.js"></script>
JsCollocation1
组件 ({PATH}/JsCollocation1.razor
):
@page "/js-collocation-1"
@inject IJSRuntime JS
<PageTitle>JS Collocation 1</PageTitle>
<h1>JS Collocation Example 1</h1>
<button @onclick="ShowPrompt">Call showPrompt1</button>
@if (!string.IsNullOrEmpty(result))
{
<p>
Hello @result!
</p>
}
@code {
private string? result;
public async void ShowPrompt()
{
result = await JS.InvokeAsync<string>(
"showPrompt1", "What's your name?");
StateHasChanged();
}
}
并置的 JS 文件放置在文件名为 JsCollocation1.razor.js
的 JsCollocation1
组件文件旁边。 在 JsCollocation1
组件中,在并置文件的路径中引用了该脚本。 在以下示例中,该 showPrompt1
函数接受来自 Window prompt()
的用户名称,并将其返回到组件 JsCollocation1
以进行显示。
{PATH}/JsCollocation1.razor.js
:
function showPrompt1(message) {
return prompt(message, 'Type your name here');
}
不建议在生产应用中普遍使用上述方法,因为它会污染具有全局功能的客户端。 生产应用适用的更好方法是使用 JS 模块。 相同的普遍原则适用于从并置的 JS 文件加载 JS 模块,如下一个示例所示。
以下 JsCollocation2
组件的 OnAfterRenderAsync
方法将 JS 模块加载到 module
,这是组件类的一个 IJSObjectReference。 module
用于调用 showPrompt2
函数。 占位符 {PATH}
是指向组件的路径。
重要
如果在测试应用中使用以下代码进行演示,请将占位符 {PATH}
更改为组件的路径。 在 Blazor Web App(.NET 8 或更高版本)中,组件需要全局应用到应用程序或组件定义的交互式呈现模式。
JsCollocation2
组件 ({PATH}/JsCollocation2.razor
):
@page "/js-collocation-2"
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>JS Collocation 2</PageTitle>
<h1>JS Collocation Example 2</h1>
<button @onclick="ShowPrompt">Call showPrompt2</button>
@if (!string.IsNullOrEmpty(result))
{
<p>
Hello @result!
</p>
}
@code {
private IJSObjectReference? module;
private string? result;
protected async override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
/*
Change the {PATH} placeholder in the next line to the path of
the collocated JS file in the app. Examples:
./Components/Pages/JsCollocation2.razor.js (.NET 8 or later)
./Pages/JsCollocation2.razor.js (.NET 7 or earlier)
*/
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./{PATH}/JsCollocation2.razor.js");
}
}
public async void ShowPrompt()
{
if (module is not null)
{
result = await module.InvokeAsync<string>(
"showPrompt2", "What's your name?");
StateHasChanged();
}
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
await module.DisposeAsync();
}
}
}
{PATH}/JsCollocation2.razor.js
:
export function showPrompt2(message) {
return prompt(message, 'Type your name here');
}
只有基于 IJSRuntime 接口的 Blazor 的 JS 互操作机制支持在 Razor 类库 (RCL) 中将脚本和模块用于并置的 JS。 如果要实现 JavaScript [JSImport]
/[JSExport]
互操作,请参阅 JavaScript Import/Export 与 ASP.NET Core Blazor 互操作。
对于由使用基于 IJSRuntime 的 JS 互操作的 Razor 类库 (RCL) 提供的脚本或模块,可使用以下路径:
./_content/{PACKAGE ID}/{PATH}/{COMPONENT}.{EXTENSION}.js
- 若要创建 JS 文件的正确静态资产路径,需要当前目录 (
./
) 的路径段。 - 占位符
{PACKAGE ID}
是 RCL 的包标识符(或由应用引用的类库的库名称)。 - 占位符
{PATH}
是指向组件的路径。 如果 Razor 组件位于 RCL 的根目录下,则不包括路径段。 - 占位符
{COMPONENT}
是组件名称。 - 占位符
{EXTENSION}
与组件的扩展名匹配,为razor
或cshtml
。
在以下 Blazor 应用示例中:
- RCL 的包标识符是
AppJS
。 - 将为
JsCollocation3
组件 (JsCollocation3.razor
) 加载模块的脚本。 JsCollocation3
组件位于 RCL 的Components/Pages
文件夹中。
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./_content/AppJS/Components/Pages/JsCollocation3.razor.js");
向多个托管的 Blazor 应用提供组件和静态资产
有关详细信息,请参阅多个托管的 ASP.NET Core Blazor WebAssembly 应用。
客户端浏览器兼容性分析器
客户端应用面向整个 .NET API 外围应用,但由于浏览器沙盒约束,并非所有 .NET API 在 WebAssembly 上都受支持。 在 WebAssembly 上运行时,不支持的 API 将引发 PlatformNotSupportedException。 当应用使用应用目标平台不支持的 API 时,平台兼容性分析器会向开发人员发出警告。 对于客户端应用,这意味着需要检查浏览器是否支持这些 API。 为兼容性分析器注释 .NET Framework API 是一个持续的过程,因此并不是所有的 .NET Framework API 当前都已进行注释。
启用交互式 WebAssembly 组件的 Blazor Web App、Blazor WebAssembly 应用和 RCL 项目会通过使用 SupportedPlatform
MSBuild 项将 browser
添加为支持的平台,以自动启用浏览器兼容性检查。 库开发人员可以手动将 SupportedPlatform
项添加到库的项目文件以启用该功能:
<ItemGroup>
<SupportedPlatform Include="browser" />
</ItemGroup>
编写库时,通过将 browser
指定为 UnsupportedOSPlatformAttribute 来指示浏览器不支持特定的 API:
using System.Runtime.Versioning;
...
[UnsupportedOSPlatform("browser")]
private static string GetLoggingDirectory()
{
...
}
有关详细信息,请参阅在特定平台(dotnet/designs
存储库)上将 API 注释为不受支持。
JavaScript 模块中的 JavaScript 隔离
Blazor 在标准 JavaScript 模块中启用 JavaScript 隔离。 JavaScript 隔离具有以下优势:
- 导入的 JavaScript 不再污染全局命名空间。
- 库和组件的使用者不需要手动导入相关的 JavaScript。
避免剪裁 JavaScript 可调用的 .NET 方法
运行时重新链接会剪裁类实例 JavaScript 可调用的 .NET 方法,除非这些方法被显式保留。 有关详细信息,请参阅在 ASP.NET Core Blazor 中从 JavaScript 函数调用 .NET 方法。
生成并打包库,再将其传送到 NuGet
由于包含 Razor 组件的 Razor 类库是标准的 .NET 库,因此将它们打包并传送到 NuGet 与将任何库打包并传送到 NuGet 没有什么区别。 在命令行界面中使用 dotnet pack
命令,执行打包操作:
dotnet pack
在命令行界面中使用 dotnet nuget push
命令,将包上传到 NuGet。
商标
Jeep 和 Jeep YJ 是 FCA 美国有限责任公司 (Stellantis NV) 的注册商标商标。