ASP.NET Core Blazor JavaScript со статическим отображением на стороне сервера (статический SSR)
Примечание.
Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 9 этой статьи.
Внимание
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см . версию .NET 9 этой статьи.
В этой статье объясняется, как загрузить JavaScript (JS) в статическую отрисовку на стороне Blazor Web App сервера (статический SSR) и расширенную навигацию.
Некоторые приложения зависят от выполнения задач инициализации, относящихся JS к каждой странице. При использовании Blazorрасширенной функции навигации, которая позволяет пользователю избежать перезагрузки всей страницы, конкретная JS страница может не выполняться повторно, как ожидалось при каждом возникновении расширенной навигации страницы.
Чтобы избежать этой проблемы, мы не рекомендуем полагаться на элементы, относящиеся к странице <script>
, расположенные за пределами файла макета, примененного к компоненту. Вместо этого скрипты должны зарегистрировать afterWebStarted
JS инициализатор для выполнения логики инициализации и использовать прослушиватель событий для прослушивания обновлений страниц, вызванных расширенной навигацией.
События
В следующих примерах прослушивателя событий заполнитель {CALLBACK}
является функцией обратного вызова.
Расширенный запуск навигации (
enhancednavigationstart
) активирует обратный вызов, прежде чем происходит улучшенная навигация:blazor.addEventListener("enhancednavigationstart", {CALLBACK});
Расширенный конец навигации (
enhancednavigationend
) активирует обратный вызов после выполнения расширенной навигации:blazor.addEventListener("enhancednavigationend", {CALLBACK});
Расширенная загрузка навигационной страницы (
enhancedload
) запускает обратный вызов каждый раз, когда страница обновляется из-за расширенной навигации, включая потоковые обновления:blazor.addEventListener("enhancedload", {CALLBACK});
Чтобы избежать этой проблемы, мы не рекомендуем полагаться на элементы, относящиеся к странице <script>
, расположенные за пределами файла макета, примененного к компоненту. Вместо этого скрипты должны зарегистрировать afterWebStarted
JS инициализатор для выполнения логики инициализации и использовать прослушиватель событий для прослушивания обновлений страниц, вызванных расширенной навигацией:
blazor.addEventListener("enhancedload", {CALLBACK});
В предыдущем примере заполнитель {CALLBACK}
является функцией обратного вызова.
Пример скрипта расширенной загрузки страницы
В следующем примере показано, как настроить JS код для запуска при первоначальной загрузке или обновлении статической отрисовки страницы с расширенной навигацией.
PageWithScript
Следующий пример компонента — это компонент в приложении, для выполнения скриптов с помощью статического SSR и расширенной навигации. Следующий пример компонента включает PageScript
компонент из Razor библиотеки классов (RCL), который добавляется в решение далее в этой статье.
Components/Pages/PageWithScript.razor
:
@page "/page-with-script"
@using BlazorPageScript
<PageTitle>Enhanced Load Script Example</PageTitle>
<PageScript Src="./Components/Pages/PageWithScript.razor.js" />
Welcome to my page.
Blazor Web AppДобавьте следующий JS с сортировкой:
-
onLoad
вызывается при добавлении скрипта на страницу. -
onUpdate
вызывается, когда скрипт по-прежнему существует на странице после расширенного обновления. -
onDispose
вызывается при удалении скрипта со страницы после расширенного обновления.
Components/Pages/PageWithScript.razor.js
:
export function onLoad() {
console.log('Loaded');
}
export function onUpdate() {
console.log('Updated');
}
export function onDispose() {
console.log('Disposed');
}
В библиотеке классов Razor (RCL) (пример RCL назван BlazorPageScript
), добавьте следующий модуль, который является инициализатором JS.
wwwroot/BlazorPageScript.lib.module.js
:
const pageScriptInfoBySrc = new Map();
function registerPageScriptElement(src) {
if (!src) {
throw new Error('Must provide a non-empty value for the "src" attribute.');
}
let pageScriptInfo = pageScriptInfoBySrc.get(src);
if (pageScriptInfo) {
pageScriptInfo.referenceCount++;
} else {
pageScriptInfo = { referenceCount: 1, module: null };
pageScriptInfoBySrc.set(src, pageScriptInfo);
initializePageScriptModule(src, pageScriptInfo);
}
}
function unregisterPageScriptElement(src) {
if (!src) {
return;
}
const pageScriptInfo = pageScriptInfoBySrc.get(src);
if (!pageScriptInfo) {
return;
}
pageScriptInfo.referenceCount--;
}
async function initializePageScriptModule(src, pageScriptInfo) {
if (src.startsWith("./")) {
src = new URL(src.substr(2), document.baseURI).toString();
}
const module = await import(src);
if (pageScriptInfo.referenceCount <= 0) {
return;
}
pageScriptInfo.module = module;
module.onLoad?.();
module.onUpdate?.();
}
function onEnhancedLoad() {
for (const [src, { module, referenceCount }] of pageScriptInfoBySrc) {
if (referenceCount <= 0) {
module?.onDispose?.();
pageScriptInfoBySrc.delete(src);
}
}
for (const { module } of pageScriptInfoBySrc.values()) {
module?.onUpdate?.();
}
}
export function afterWebStarted(blazor) {
customElements.define('page-script', class extends HTMLElement {
static observedAttributes = ['src'];
attributeChangedCallback(name, oldValue, newValue) {
if (name !== 'src') {
return;
}
this.src = newValue;
unregisterPageScriptElement(oldValue);
registerPageScriptElement(newValue);
}
disconnectedCallback() {
unregisterPageScriptElement(this.src);
}
});
blazor.addEventListener('enhancedload', onEnhancedLoad);
}
Не добавляйте тег <script>
в корневой компонент приложения, который, как правило, является компонентом App
, BlazorPageScript.lib.module.js
, потому что модуль в данном случае является JS инициализатором (afterWebStarted
).
JS инициализаторы автоматически обнаруживаются и загружаются фреймворком Blazor.
Добавьте следующий PageScript
компонент в RCL.
PageScript.razor
:
<page-script src="@Src"></page-script>
@code {
[Parameter]
[EditorRequired]
public string Src { get; set; } = default!;
}
Компонент PageScript
обычно работает на верхнем уровне страницы.
Если вы помещаете PageScript
компонент в макет приложения (например, MainLayout.razor
), что приводит к общему PageScript
доступу между страницами, используюющими макет, компонент запускается onLoad
только после полной перезагрузки страницы и onUpdate
при возникновении любого расширенного обновления страницы, включая улучшенную навигацию.
Чтобы повторно использовать один и тот же модуль между страницами, но вызовы onLoad
и onDispose
обратные вызовы, вызываемые при каждом изменении страницы, добавьте строку запроса в конец скрипта, чтобы он распознался как другой модуль. Приложение может принять соглашение об использовании имени компонента в качестве значения строки запроса. В следующем примере строка запроса имеет значение "counter
", так как ссылка на этот PageScript
компонент помещается в Counter
компонент. Это просто предложение, и вы можете использовать любую схему строки запроса, которую вы предпочитаете.
<PageScript Src="./Components/Pages/PageWithScript.razor.js?counter" />
Чтобы отслеживать изменения в определенных элементах DOM, используйте MutationObserver
шаблон в JS клиенте. Дополнительные сведения см. в разделе Взаимодействие JavaScript приложения Blazor ASP.NET Core (взаимодействие JS).
Реализация без использования RCL
Описанный в этой статье подход можно реализовать непосредственно в Blazor Web App без использования библиотеки классов Razor (RCL), переместив ресурсы RCL в приложение. Однако использование RCL удобно, так как RCL может быть упаковано в пакет NuGet для использования Blazor приложениями в организации.
При перемещении ресурсов в Blazor Web Appобязательно переименуйте модуль (BlazorPageScript.lib.module.js
), чтобы он соответствовал приложению и правилам именования файлов для инициализаторов JS. Если файл не называется правильно, Blazor не удается обнаружить и загрузить модуль, а событие afterWebStarted
не выполняется автоматически при запуске приложения.
ASP.NET Core