Blazor JavaScript 互操作性(JS 互操作)

Blazor 应用可从 .NET 方法调用 JavaScript (JS) 函数,也可从 JS 函数调用 .NET 方法。 这被称为 JavaScript 互操作性(JS 互操作) 。

本概述文章涵盖了常规概念。 以下文章中提供了进一步的 JS 互操作指南:

与 DOM 文档对象模型 (DOM) 交互

仅在对象不与 Blazor 对象交互时,才使用 JavaScript (JS) 改变文档对象模型 (DOM)。 Blazor 维护 DOM 的表示形式,并直接与 DOM 对象交互。 如果 Blazor 呈现的元素直接使用 JS 或通过 JS 互操作在外部修改,DOM 可能不再匹配 Blazor 的内部表示形式,这可能会导致未定义行为。 未定义行为可能只会干扰元素及其功能的呈现,但也可能给应用或服务器带来安全风险。

本指南不仅适用于你自己的 JS 互操作代码,还适用于应用使用的任何 JS 库,包括第三方框架提供的任何内容,例如 Bootstrap JSjQuery

在一些文档示例中,JS 互操作用于改变元素,纯粹用于示例中的演示目的。 在这些情况下,文本中会出现警告。

有关详细信息,请参阅 在 ASP.NET Core Blazor 中从 .NET 方法调用 JavaScript 函数

异步 JavaScript 调用

默认情况下,JS 互操作调用是异步的,无论调用的代码是同步还是异步。 默认情况下,调用是异步的,以确保组件在 Blazor 托管模型 Blazor Server 和 Blazor WebAssembly 之间兼容。 在 Blazor Server 上,JS 互操作调用必须是异步的,因为它们是通过网络连接发送的。 对于完全采用 Blazor WebAssembly 托管模型的应用,支持同步的 JS 互操作调用。 有关详细信息,请参阅 ASP.NET Core Blazor 性能最佳做法

JavaScipt 的位置

使用以下任一方法加载 JavaScript (JS) 代码:

警告

请勿将 <script> 标记置于 Razor 组件文件 (.razor) 中,因为 <script> 标记无法由 Blazor 动态更新。

备注

文档示例通常将脚本置于 <script> 标记中,或从外部文件加载全局脚本。 这些方法使用全局函数污染客户端。 对于生产应用,建议将 JavaScript 置于单独的 JavaScript 模块中,以便在需要时可进行导入。 有关详细信息,请参阅 JavaScript 模块中的 JavaScript 隔离部分。

<head> 标记中加载脚本

通常不建议使用本部分中的这个方法。

将脚本 (<script>...</script>) 置于 wwwroot/index.html (Blazor WebAssembly) 或 Pages/_Layout.cshtml (Blazor Server) 的<head> 元素标记中:

<head>
    ...

    <script>
      window.jsMethod = (methodParameter) => {
        ...
      };
    </script>
</head>

<head> 加载 JS 并不是最好的方法,原因如下:

  • 如果脚本依赖于 Blazor,JS 互操作可能会失败。 建议使用一种其他方法加载脚本,而不是通过 <head> 标记加载脚本。
  • 由于分析脚本中的 JS 需要时间,页面的交互速度可能会变慢。

<body> 标记中加载脚本

将脚本 (<script>...</script>) 置于 wwwroot/index.html (Blazor WebAssembly) 或 Pages/_Layout.cshtml (Blazor Server) 的结束 </body> 元素标记中:

<body>
    ...

    <script src="_framework/blazor.{webassembly|server}.js"></script>
    <script>
      window.jsMethod = (methodParameter) => {
        ...
      };
    </script>
</body>

前面标记中的 {webassembly|server} 占位符是 Blazor WebAssembly 应用 (blazor.webassembly.js) 的 webassembly 或 Blazor Server 应用 (blazor.server.js) 的 server

从外部 JS 文件 (.js) 加载脚本

将带有脚本 src 路径的脚本 (<script>...</script>) 置于 Blazor 脚本引用后的结束 </body> 标记中。

wwwroot/index.html (Blazor WebAssembly) 或 Pages/_Layout.cshtml (Blazor Server) 中:

<body>
    ...

    <script src="_framework/blazor.{webassembly|server}.js"></script>
    <script src="{SCRIPT PATH AND FILE NAME (.js)}"></script>
</body>

前面标记中的 {webassembly|server} 占位符是 Blazor WebAssembly 应用 (blazor.webassembly.js) 的 webassembly 或 Blazor Server 应用 (blazor.server.js) 的 server{SCRIPT PATH AND FILE NAME (.js)} 占位符是 wwwroot 下的路径和脚本文件名。

在以下前述 <script> 标记的示例中,scripts.js 文件位于应用的 wwwroot/js 文件夹中:

<script src="js/scripts.js"></script>

当外部 JS 文件由 Razor 类库提供时,使用其稳定的静态 Web 资产路径 ./_content/{PACKAGE ID}/{SCRIPT PATH AND FILENAME (.js)} 指定 JS 文件:

  • 若要创建 JS 文件的正确静态资产路径,需要当前目录 (./) 的路径段。
  • {PACKAGE ID} 占位符是库的包 ID。 如果项目文件中没有指定 <PackageId>,则包 ID 默认为项目的程序集名称。
  • {SCRIPT PATH AND FILENAME (.js)} 占位符是 wwwroot 下的路径和文件名。
<body>
    ...

    <script src="_framework/blazor.{webassembly|server}.js"></script>
    <script src="./_content/{PACKAGE ID}/{SCRIPT PATH AND FILENAME (.js)}"></script>
</body>

在以下前述 <script> 标记的示例中:

  • Razor 类库的程序集名称为 ComponentLibrary,并且库的项目文件中没有指定 <PackageId>
  • scripts.js 文件位于类库的 wwwroot 文件夹中。
<script src="./_content/ComponentLibrary/scripts.js"></script>

有关详细信息,请参阅 使用 Razor 类库中的 ASP.NET Core Razor 组件

在 Blazor 启动后注入脚本

在应用初始化时,从 wwwroot/index.html (Blazor WebAssembly) 或 Pages/_Layout.cshtml (Blazor Server) 中注入的脚本加载 JS:

  • autostart="false" 添加到加载 Blazor 脚本的 <script> 标记中。
  • 在通过调用 Blazor.start().then(...) 启动 Blazor 之后,向 <head> 元素标记中注入一个引用自定义 JS 文件的脚本。 在加载 Blazor 脚本之后,将脚本 (<script>...</script>) 置于结束的 </body> 标记中。

以下示例在 wwwroot/scripts.js 启动后注入文件 Blazor:

<body>
    ...

    <script src="_framework/blazor.{webassembly|server}.js" 
        autostart="false"></script>
    <script>
      Blazor.start().then(function () {
        var customScript = document.createElement('script');
        customScript.setAttribute('src', 'scripts.js');
        document.head.appendChild(customScript);
      });
    </script>
</body>

前面标记中的 {webassembly|server} 占位符是 Blazor WebAssembly 应用 (blazor.webassembly.js) 的 webassembly 或 Blazor Server 应用 (blazor.server.js) 的 server

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

JavaScript 模块中的 JavaScript 隔离

Blazor 在标准 JavaScript 模块ECMAScript 规范)中启用 JavaScript (JS) 隔离。

JS 隔离具有以下优势:

  • 导入的 JS 不再污染全局命名空间。
  • 库和组件的使用者不需要导入相关的 JS。

有关详细信息,请参阅 在 ASP.NET Core Blazor 中从 .NET 方法调用 JavaScript 函数

缓存的 JavaScript 文件

Development 环境中进行开发时,JavaScript (JS) 文件和其他静态资产通常不会缓存在客户端上。 在开发过程中,静态资产请求包含值为 no-cachemax-age(值为零 (0))的 Cache-Control 标头

Production 环境中的生产阶段,JS 文件通常由客户端缓存。

若要在浏览器中禁用客户端缓存,开发人员通常采用以下方法之一:

有关详细信息,请参阅:

Blazor 应用可从 .NET 方法调用 JavaScript (JS) 函数,也可从 JS 函数调用 .NET 方法。 这被称为 JavaScript 互操作性(JS 互操作) 。

本概述文章涵盖了常规概念。 以下文章中提供了进一步的 JS 互操作指南:

与 DOM 文档对象模型 (DOM) 交互

仅在对象不与 Blazor 对象交互时,才使用 JavaScript (JS) 改变文档对象模型 (DOM)。 Blazor 维护 DOM 的表示形式,并直接与 DOM 对象交互。 如果 Blazor 呈现的元素直接使用 JS 或通过 JS 互操作在外部修改,DOM 可能不再匹配 Blazor 的内部表示形式,这可能会导致未定义行为。 未定义行为可能只会干扰元素及其功能的呈现,但也可能给应用或服务器带来安全风险。

本指南不仅适用于你自己的 JS 互操作代码,还适用于应用使用的任何 JS 库,包括第三方框架提供的任何内容,例如 Bootstrap JSjQuery

在一些文档示例中,JS 互操作用于改变元素,纯粹用于示例中的演示目的。 在这些情况下,文本中会出现警告。

有关详细信息,请参阅 在 ASP.NET Core Blazor 中从 .NET 方法调用 JavaScript 函数

异步 JavaScript 调用

默认情况下,JS 互操作调用是异步的,无论调用的代码是同步还是异步。 默认情况下,调用是异步的,以确保组件在 Blazor 托管模型 Blazor Server 和 Blazor WebAssembly 之间兼容。 在 Blazor Server 上,JS 互操作调用必须是异步的,因为它们是通过网络连接发送的。 对于完全采用 Blazor WebAssembly 托管模型的应用,支持同步的 JS 互操作调用。 有关详细信息,请参阅 ASP.NET Core Blazor 性能最佳做法

JavaScipt 的位置

使用以下任一方法加载 JavaScript (JS) 代码:

警告

请勿将 <script> 标记置于 Razor 组件文件 (.razor) 中,因为 <script> 标记无法由 Blazor 动态更新。

备注

文档示例通常将脚本置于 <script> 标记中,或从外部文件加载全局脚本。 这些方法使用全局函数污染客户端。 对于生产应用,建议将 JavaScript 置于单独的 JavaScript 模块中,以便在需要时可进行导入。 有关详细信息,请参阅 JavaScript 模块中的 JavaScript 隔离部分。

<head> 标记中加载脚本

通常不建议使用本部分中的这个方法。

将脚本 (<script>...</script>) 置于 wwwroot/index.html (Blazor WebAssembly) 或 Pages/_Host.cshtml (Blazor Server) 的<head> 元素标记中:

<head>
    ...

    <script>
      window.jsMethod = (methodParameter) => {
        ...
      };
    </script>
</head>

<head> 加载 JS 并不是最好的方法,原因如下:

  • 如果脚本依赖于 Blazor,JS 互操作可能会失败。 建议使用一种其他方法加载脚本,而不是通过 <head> 标记加载脚本。
  • 由于分析脚本中的 JS 需要时间,页面的交互速度可能会变慢。

<body> 标记中加载脚本

将脚本 (<script>...</script>) 置于 wwwroot/index.html (Blazor WebAssembly) 或 Pages/_Host.cshtml (Blazor Server) 的结束 </body> 元素标记中:

<body>
    ...

    <script src="_framework/blazor.{webassembly|server}.js"></script>
    <script>
      window.jsMethod = (methodParameter) => {
        ...
      };
    </script>
</body>

前面标记中的 {webassembly|server} 占位符是 Blazor WebAssembly 应用 (blazor.webassembly.js) 的 webassembly 或 Blazor Server 应用 (blazor.server.js) 的 server

从外部 JS 文件 (.js) 加载脚本

将带有脚本 src 路径的脚本 (<script>...</script>) 置于 Blazor 脚本引用后的结束 </body> 标记中。

wwwroot/index.html (Blazor WebAssembly) 或 Pages/_Host.cshtml (Blazor Server) 中:

<body>
    ...

    <script src="_framework/blazor.{webassembly|server}.js"></script>
    <script src="{SCRIPT PATH AND FILE NAME (.js)}"></script>
</body>

前面标记中的 {webassembly|server} 占位符是 Blazor WebAssembly 应用 (blazor.webassembly.js) 的 webassembly 或 Blazor Server 应用 (blazor.server.js) 的 server{SCRIPT PATH AND FILE NAME (.js)} 占位符是 wwwroot 下的路径和脚本文件名。

在以下前述 <script> 标记的示例中,scripts.js 文件位于应用的 wwwroot/js 文件夹中:

<script src="js/scripts.js"></script>

当外部 JS 文件由 Razor 类库提供时,使用其稳定的静态 Web 资产路径 ./_content/{PACKAGE ID}/{SCRIPT PATH AND FILENAME (.js)} 指定 JS 文件:

  • 若要创建 JS 文件的正确静态资产路径,需要当前目录 (./) 的路径段。
  • {PACKAGE ID} 占位符是库的包 ID。 如果项目文件中没有指定 <PackageId>,则包 ID 默认为项目的程序集名称。
  • {SCRIPT PATH AND FILENAME (.js)} 占位符是 wwwroot 下的路径和文件名。
<body>
    ...

    <script src="_framework/blazor.{webassembly|server}.js"></script>
    <script src="./_content/{PACKAGE ID}/{SCRIPT PATH AND FILENAME (.js)}"></script>
</body>

在以下前述 <script> 标记的示例中:

  • Razor 类库的程序集名称为 ComponentLibrary,并且库的项目文件中没有指定 <PackageId>
  • scripts.js 文件位于类库的 wwwroot 文件夹中。
<script src="./_content/ComponentLibrary/scripts.js"></script>

有关详细信息,请参阅 使用 Razor 类库中的 ASP.NET Core Razor 组件

在 Blazor 启动后注入脚本

在应用初始化时,从 wwwroot/index.html (Blazor WebAssembly) 或 Pages/_Host.cshtml (Blazor Server) 中注入的脚本加载 JS:

  • autostart="false" 添加到加载 Blazor 脚本的 <script> 标记中。
  • 在通过调用 Blazor.start().then(...) 启动 Blazor 之后,向 <head> 元素标记中注入一个引用自定义 JS 文件的脚本。 在加载 Blazor 脚本之后,将脚本 (<script>...</script>) 置于结束的 </body> 标记中。

以下示例在 wwwroot/scripts.js 启动后注入文件 Blazor:

<body>
    ...

    <script src="_framework/blazor.{webassembly|server}.js" 
        autostart="false"></script>
    <script>
      Blazor.start().then(function () {
        var customScript = document.createElement('script');
        customScript.setAttribute('src', 'scripts.js');
        document.head.appendChild(customScript);
      });
    </script>
</body>

前面标记中的 {webassembly|server} 占位符是 Blazor WebAssembly 应用 (blazor.webassembly.js) 的 webassembly 或 Blazor Server 应用 (blazor.server.js) 的 server

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

JavaScript 模块中的 JavaScript 隔离

Blazor 在标准 JavaScript 模块ECMAScript 规范)中启用 JavaScript (JS) 隔离。

JS 隔离具有以下优势:

  • 导入的 JS 不再污染全局命名空间。
  • 库和组件的使用者不需要导入相关的 JS。

有关详细信息,请参阅 在 ASP.NET Core Blazor 中从 .NET 方法调用 JavaScript 函数

缓存的 JavaScript 文件

Development 环境中进行开发时,JavaScript (JS) 文件和其他静态资产通常不会缓存在客户端上。 在开发过程中,静态资产请求包含值为 no-cachemax-age(值为零 (0))的 Cache-Control 标头

Production 环境中的生产阶段,JS 文件通常由客户端缓存。

若要在浏览器中禁用客户端缓存,开发人员通常采用以下方法之一:

有关详细信息,请参阅:

Blazor 应用可从 .NET 方法调用 JavaScript (JS) 函数,也可从 JS 函数调用 .NET 方法。 这被称为 JavaScript 互操作性(JS 互操作) 。

本概述文章涵盖了常规概念。 以下文章中提供了进一步的 JS 互操作指南:

与 DOM 文档对象模型 (DOM) 交互

仅在对象不与 Blazor 对象交互时,才使用 JavaScript (JS) 改变文档对象模型 (DOM)。 Blazor 维护 DOM 的表示形式,并直接与 DOM 对象交互。 如果 Blazor 呈现的元素直接使用 JS 或通过 JS 互操作在外部修改,DOM 可能不再匹配 Blazor 的内部表示形式,这可能会导致未定义行为。 未定义行为可能只会干扰元素及其功能的呈现,但也可能给应用或服务器带来安全风险。

本指南不仅适用于你自己的 JS 互操作代码,还适用于应用使用的任何 JS 库,包括第三方框架提供的任何内容,例如 Bootstrap JSjQuery

在一些文档示例中,JS 互操作用于改变元素,纯粹用于示例中的演示目的。 在这些情况下,文本中会出现警告。

有关详细信息,请参阅 在 ASP.NET Core Blazor 中从 .NET 方法调用 JavaScript 函数

异步 JavaScript 调用

默认情况下,JS 互操作调用是异步的,无论调用的代码是同步还是异步。 默认情况下,调用是异步的,以确保组件在 Blazor 托管模型 Blazor Server 和 Blazor WebAssembly 之间兼容。 在 Blazor Server 上,JS 互操作调用必须是异步的,因为它们是通过网络连接发送的。 对于完全采用 Blazor WebAssembly 托管模型的应用,支持同步的 JS 互操作调用。 有关详细信息,请参阅 ASP.NET Core Blazor 性能最佳做法

JavaScipt 的位置

使用以下任一方法加载 JavaScript (JS) 代码:

警告

请勿将 <script> 标记置于 Razor 组件文件 (.razor) 中,因为 <script> 标记无法由 Blazor 动态更新。

备注

文档示例将脚本置于 <script> 标记中,或从外部文件加载全局脚本。 这些方法使用全局函数污染客户端。 在 ASP.NET Core 5.0 之前的 Blazor 版本中,不支持将 JavaScript 置于单独的 JavaScript 模块(以供在需要时导入)。 如果应用需要使用 JS 模块来进行 JS 隔离,建议使用 ASP.NET Core 5.0 或更高版本来生成应用。 有关详细信息,请使用“版本”下拉列表选择本文的 5.0 或更高版本,并查看“JavaScript 模块中的 JavaScript 隔离”部分。

<head> 标记中加载脚本

通常不建议使用本部分中的这个方法。

将脚本 (<script>...</script>) 置于 wwwroot/index.html (Blazor WebAssembly) 或 Pages/_Host.cshtml (Blazor Server) 的<head> 元素标记中:

<head>
    ...

    <script>
      window.jsMethod = (methodParameter) => {
        ...
      };
    </script>
</head>

<head> 加载 JS 并不是最好的方法,原因如下:

  • 如果脚本依赖于 Blazor,JS 互操作可能会失败。 建议使用一种其他方法加载脚本,而不是通过 <head> 标记加载脚本。
  • 由于分析脚本中的 JS 需要时间,页面的交互速度可能会变慢。

<body> 标记中加载脚本

将脚本 (<script>...</script>) 置于 wwwroot/index.html (Blazor WebAssembly) 或 Pages/_Host.cshtml (Blazor Server) 的结束 </body> 元素标记中:

<body>
    ...

    <script src="_framework/blazor.{webassembly|server}.js"></script>
    <script>
      window.jsMethod = (methodParameter) => {
        ...
      };
    </script>
</body>

前面标记中的 {webassembly|server} 占位符是 Blazor WebAssembly 应用 (blazor.webassembly.js) 的 webassembly 或 Blazor Server 应用 (blazor.server.js) 的 server

从外部 JS 文件 (.js) 加载脚本

将带有脚本 src 路径的脚本 (<script>...</script>) 置于 Blazor 脚本引用后的结束 </body> 标记中。

wwwroot/index.html (Blazor WebAssembly) 或 Pages/_Host.cshtml (Blazor Server) 中:

<body>
    ...

    <script src="_framework/blazor.{webassembly|server}.js"></script>
    <script src="{SCRIPT PATH AND FILE NAME (.js)}"></script>
</body>

前面标记中的 {webassembly|server} 占位符是 Blazor WebAssembly 应用 (blazor.webassembly.js) 的 webassembly 或 Blazor Server 应用 (blazor.server.js) 的 server{SCRIPT PATH AND FILE NAME (.js)} 占位符是 wwwroot 下的路径和脚本文件名。

在以下前述 <script> 标记的示例中,scripts.js 文件位于应用的 wwwroot/js 文件夹中:

<script src="js/scripts.js"></script>

当外部 JS 文件由 Razor 类库提供时,使用其稳定的静态 Web 资产路径 ./_content/{PACKAGE ID}/{SCRIPT PATH AND FILENAME (.js)} 指定 JS 文件:

  • 若要创建 JS 文件的正确静态资产路径,需要当前目录 (./) 的路径段。
  • {PACKAGE ID} 占位符是库的包 ID。 如果项目文件中没有指定 <PackageId>,则包 ID 默认为项目的程序集名称。
  • {SCRIPT PATH AND FILENAME (.js)} 占位符是 wwwroot 下的路径和文件名。
<body>
    ...

    <script src="_framework/blazor.{webassembly|server}.js"></script>
    <script src="./_content/{PACKAGE ID}/{SCRIPT PATH AND FILENAME (.js)}"></script>
</body>

在以下前述 <script> 标记的示例中:

  • Razor 类库的程序集名称为 ComponentLibrary,并且库的项目文件中没有指定 <PackageId>
  • scripts.js 文件位于类库的 wwwroot 文件夹中。
<script src="./_content/ComponentLibrary/scripts.js"></script>

有关详细信息,请参阅 使用 Razor 类库中的 ASP.NET Core Razor 组件

在 Blazor 启动后注入脚本

在应用初始化时,从 wwwroot/index.html (Blazor WebAssembly) 或 Pages/_Host.cshtml (Blazor Server) 中注入的脚本加载 JS:

  • autostart="false" 添加到加载 Blazor 脚本的 <script> 标记中。
  • 在通过调用 Blazor.start().then(...) 启动 Blazor 之后,向 <head> 元素标记中注入一个引用自定义 JS 文件的脚本。 在加载 Blazor 脚本之后,将脚本 (<script>...</script>) 置于结束的 </body> 标记中。

以下示例在 wwwroot/scripts.js 启动后注入文件 Blazor:

<body>
    ...

    <script src="_framework/blazor.{webassembly|server}.js" 
        autostart="false"></script>
    <script>
      Blazor.start().then(function () {
        var customScript = document.createElement('script');
        customScript.setAttribute('src', 'scripts.js');
        document.head.appendChild(customScript);
      });
    </script>
</body>

前面标记中的 {webassembly|server} 占位符是 Blazor WebAssembly 应用 (blazor.webassembly.js) 的 webassembly 或 Blazor Server 应用 (blazor.server.js) 的 server

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

缓存的 JavaScript 文件

Development 环境中进行开发时,JavaScript (JS) 文件和其他静态资产通常不会缓存在客户端上。 在开发过程中,静态资产请求包含值为 no-cachemax-age(值为零 (0))的 Cache-Control 标头

Production 环境中的生产阶段,JS 文件通常由客户端缓存。

若要在浏览器中禁用客户端缓存,开发人员通常采用以下方法之一:

有关详细信息,请参阅: