Поделиться через


Расположение JavaScript в приложениях ASP.NET Core Blazor

Примечание.

Это не последняя версия этой статьи. Для текущего выпуска, смотрите версию .NET 9 этой статьи.

Предупреждение

Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. Для текущего выпуска, смотрите версию .NET 9 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

Для текущего выпуска, смотрите версию .NET 9 этой статьи.

Загрузите код JavaScript (JS) одним из следующих способов:

Встроенный JavaScript не рекомендуется использовать для Blazor приложений. Мы рекомендуем использовать JS collocation в сочетании с модулями JS.

Расположение тегов <script>

Размещайте тег <script> в файл компонента (.razor) только если гарантировано, что компонент будет использовать статическую серверную отрисовку без расширенной навигации. Размещение тега <script> в файле компонента не создает предупреждение во время компиляции или ошибку, но поведение загрузки скрипта может не соответствовать вашим ожиданиям в компонентах, которые принимают интерактивный режим отрисовки или статический SSR с улучшенной навигацией.

Не помещайте тег <script> в файл компонента (.razor), так как тег <script> не может изменяться динамически. Размещение тега <script> в файле компонента приводит к ошибке во время компиляции.

Примечание.

В примерах из документации скрипты обычно размещают в теге <script> или загружают глобальные скрипты из внешних файлов. Такие способы приводят к засорению клиента глобальными функциями. Для производственных приложений мы рекомендуем помещать JS в отдельные JS модули, которые можно импортировать при необходимости. Дополнительные сведения см. в разделе Изоляция JavaScript в модулях JavaScript.

Примечание.

В примерах из документации скрипты размещают в теге <script> или загружают глобальные скрипты из внешних файлов. Такие способы приводят к засорению клиента глобальными функциями. Размещение JS в отдельныхJS модулях, которые можно импортировать по мере необходимости, не поддерживается в версиях до .NET 5. Если приложению требуется использование JS модулей для JS изоляции, рекомендуется использовать .NET 5 или более поздней версии для создания приложения. Дополнительные сведения см. в выпадающем списке "Версия", чтобы выбрать версию .NET 5 или более позднюю и просмотреть раздел изоляция JavaScript в модулях JavaScript.

Загрузка скрипта в разметку <head>

Описанный в этом разделе подход обычно не рекомендуется использовать.

Поместите теги JavaScript (JS<script>...</script>) в разметку <head>элемента:

<head>
    ...

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

Загрузка JS из <head> не является оптимальным способом по следующим причинам:

  • Взаимодействие JS может завершиться ошибкой, если скрипт зависит от Blazor. Мы рекомендуем загружать скрипты с помощью других методов, а не через разметку <head>.
  • Страница может стать интерактивной медленнее из-за времени, необходимого для анализа JS в скрипте.

В разметке компонентов скрипты можно загружать с помощью компонента HeadContent с обычным предупреждением о том, что подход замедляет загрузку страницы на клиенте, что рекомендуется избегать. Если скрипт загружается с компонентом HeadContent в приложении Blazor Server, Blazor WebAssembly или Blazor Web App, используя либо интерактивный режим отрисовки (интерактивный SSR, CSR), либо статический SSR с улучшенной навигацией, переход от страницы компонента удаляет тег <script> из отрисованного <head> содержимого, но не выгружает код JavaScript скрипта, включая обработчики событий, которые регистрируются скриптом, и переменные и методы, предоставляемые скриптом. Только Blazor Web Appс использованием статического SSR без улучшенной навигации выгружают код JavaScript, когда пользователь покидает страницу. Как правило, вам лучше добавить теги <script> в физическое <head> содержимое, если вы явно хотите хранить такие ссылки на скрипты в компонентах, которые используют их, и не против, что код не выгружается при навигационных событиях.

В разметке компонентов скрипты можно загружать с помощью компонента HeadContent с обычным предупреждением о том, что подход замедляет загрузку страницы на клиенте, что рекомендуется избегать. При загрузке скрипта с помощью компонента HeadContent переход от страницы компонента удаляет тег <script> из отрисованного содержимого <head>, но не выгружает код JavaScript скрипта, включая обработчики событий, регистрируемые скриптом, а также предоставляемые скриптом переменные и методы. Как правило, вам лучше добавить теги <script> в физическое <head> содержимое, если вы явно хотите хранить такие ссылки на скрипты в компонентах, которые используют их, и не против, что код не выгружается при навигационных событиях.

Загрузка скрипта в разметку <body>

Поместите теги JavaScript (<script>...</script>) внутри закрывающего </body> элемента после Blazor ссылки на скрипт:

<body>
    ...

    <script src="{BLAZOR SCRIPT}"></script>
    <script>
      window.jsMethod = (methodParameter) => {
        ...
      };
    </script>
</body>

В предыдущем примере {BLAZOR SCRIPT} является заполнителем для пути к скрипту и имени файла Blazor. Сведения о расположении скрипта см. в разделе структура проекта ASP.NET Core.

Загрузите скрипт из внешнего файла JavaScript (.js), размещенного совместно с компонентом

Совместное размещение файлов JavaScript (JS) для Razor компонентов — удобный способ упорядочивания скриптов в приложении.

Razor Компоненты приложений Blazor упорядочивают JS файлы, используя расширение .razor.js, и могут быть общедоступны с помощью пути к файлу в проекте:

{PATH}/{COMPONENT}.razor.js

  • Заполнитель {PATH} — это путь к компоненту.
  • Заполнитель {COMPONENT} — это компонент.

При публикации приложения платформа автоматически перемещает скрипт в корневой каталог. Скрипты перемещаются в bin/Release/{TARGET FRAMEWORK MONIKER}/publish/wwwroot/{PATH}/{COMPONENT}.razor.js, где находятся заполнители.

Изменений для относительного URL-адреса скрипта не требуется, поскольку Blazor автоматически размещает файл JS в опубликованных статических ресурсах.

В этом разделе и приведенных ниже примерах основное внимание уделяется объяснению JS расположения файлов. В первом примере демонстрируется совместно расположенный JS файл с обычной JS функцией. Второй пример демонстрирует использование модуля для загрузки функции, которая является рекомендуемой подходом для большинства рабочих приложений. Вызов JS из .NET полностью раскрыт в статье Вызов функций JavaScript из методов .NET в ASP.NET Core Blazor, где представлено дальнейшее объяснение API BlazorJS с примерами. Удаление компонентов, которое представлено во втором примере, обсуждается в ASP.NET Core Razor удалении компонентов.

Следующий JsCollocation1 компонент загружает скрипт с помощью HeadContent компонента и вызывает JS функцию с IJSRuntime.InvokeAsync. Заполнитель {PATH} — это путь к компоненту.

Внимание

Если вы используете следующий код для демонстрации в тестовом приложении, измените {PATH} заполнитель на путь компонента (например, Components/Pages в .NET 8 или более поздней версии или Pages в .NET 7 или более ранней версии). В компоненте 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 Task ShowPrompt()
    {
        result = await JS.InvokeAsync<string>(
            "showPrompt1", "What's your name?");
        StateHasChanged();
    }
}

Совместно расположенный файл JS помещается рядом с файлом компонента JsCollocation1 с именем JsCollocation1.razor.js. В компоненте 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 Task 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)
        {
            try
            {
                await module.DisposeAsync();
            }
            catch (JSDisconnectedException)
            {
            }
        }
    }
}

В предыдущем примере JSDisconnectedException остаётся в процессе удаления модуля, если контур BlazorSignalR потерян. Если предыдущий код используется в Blazor WebAssembly приложении, нет подключения, которое можно потерять, SignalR поэтому можно удалить блок и оставить строку, которая освобождает try-catch модуль (await module.DisposeAsync();). Дополнительные сведения см. в разделе Интероперабельность JavaScript в ASP.NET Core Blazor (JS interop).

{PATH}/JsCollocation2.razor.js:

export function showPrompt2(message) {
  return prompt(message, 'Type your name here');
}

Внимание

Не размещайте тег <script> для JsCollocation2.razor.js после скрипта Blazor, так как модуль загружается и кэшируется автоматически при вызове динамического import().

Использование скриптов и модулей для сортировки JS в Razor библиотеке классов (RCL) поддерживается только для BlazorJS механизма взаимодействия на IJSRuntime основе интерфейса. Если вы реализуете взаимодействие с JavaScript, ознакомьтесь с импортом/экспортом JS в ASP.NET Core.

Для сценариев или модулей, предоставляемых библиотекой Razor классов (RCL) с помощью взаимодействия на основе IJSRuntimeJS, используется следующий путь:

./_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 находится в папке Components/Pages библиотеки RCL.
module = await JS.InvokeAsync<IJSObjectReference>("import", 
    "./_content/AppJS/Components/Pages/JsCollocation3.razor.js");

Дополнительные сведения о RCL см. в статье Использование компонентов Razor в ASP.NET Core из библиотеки классов Razor (RCL).

Загрузите скрипт из внешнего файла JavaScript (.js)

Поместите теги JavaScript (JS) с источником скрипта (<script>...</script>src) путь внутри закрывающего </body> элемента после Blazor ссылки на скрипт:

<body>
    ...

    <script src="{BLAZOR SCRIPT}"></script>
    <script src="{SCRIPT PATH AND FILE NAME (.js)}"></script>
</body>

Для заполнителей в предыдущем примере:

  • Заполнитель {BLAZOR SCRIPT} — это путь к скрипту Blazor и имя файла. Сведения о расположении скрипта см. в разделе структура проекта ASP.NET Core.
  • Заполнитель {SCRIPT PATH AND FILE NAME (.js)} — это путь и имя файла скрипта в папке wwwroot.

В следующем примере для предыдущего тега <script> файл scripts.js находится в папке wwwroot/js приложения:

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

Вы также можете обслуживать скрипты непосредственно из wwwroot папки, если вы предпочитаете не хранить все скрипты в отдельной папке в wwwrootпапке:

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

Если внешний файл JS предоставляется библиотекой классов Razor, укажите файл JS, используя его стабильный путь к статическому веб-активу _content/{PACKAGE ID}/{SCRIPT PATH AND FILE NAME (.js)}.

  • Заполнитель {PACKAGE ID} — это идентификатор пакета библиотеки. Идентификатор пакета по умолчанию имеет имя сборки проекта, если значение <PackageId> не указано в файле проекта.
  • Заполнитель {SCRIPT PATH AND FILE NAME (.js)} — это путь и имя файла в папке wwwroot.
<body>
    ...

    <script src="{BLAZOR SCRIPT}"></script>
    <script src="_content/{PACKAGE ID}/{SCRIPT PATH AND FILE NAME (.js)}"></script>
</body>

На примере предыдущего тега <script>:

  • Библиотека классов Razor имеет имя сборки ComponentLibrary, а значение <PackageId> не указано в файле проекта библиотеки.
  • Файл scripts.js находится в папке библиотеки классов wwwroot.
<script src="_content/ComponentLibrary/scripts.js"></script>

Дополнительные сведения см. в статье Использование компонентов Razor в ASP.NET Core из библиотеки классов Razor (RCL).

Внедрить скрипт до или после запуска Blazor.

Чтобы обеспечить загрузку скриптов до или после Blazor запуска, используйте инициализатор JavaScript. Дополнительные сведения и примеры см. в разделе ASP.NET Core Blazor стартап.

Внедрение скрипта после запуска Blazor

Чтобы внедрить скрипт после запуска Blazor, свяжитесь с Promise, который возникает из-за ручного запуска Blazor. Дополнительные сведения и пример см. в разделе ASP.NET CoreBlazor startup.

Изоляция JavaScript в модулях JavaScript

Blazorобеспечивает изоляцию JavaScript (JS) в стандартныхJSмодулях (спецификация ECMAScript).

Изоляция JS обеспечивает следующие преимущества:

  • Импортированный JS не засоряет глобальное пространство имен.
  • Пользователям библиотеки и компонентов не требуется импортировать связанный код JS.

В серверных сценариях всегда обрабатывайте JSDisconnectedException, в случае если потеря цепи BlazorSignalR предотвращает вызов взаимодействия JS от освобождения модуля, что приводит к необработанному исключению. Blazor WebAssembly приложения не используют SignalR подключение во время JS взаимодействия, поэтому нет необходимости отлавливать JSDisconnectedException в Blazor WebAssembly приложениях для освобождения модулей.

Дополнительные сведения см. на следующих ресурсах: