ASP.NET Core Blazor JavaScript со статическим отображением на стороне сервера (статический SSR)
В этой статье объясняется, как загрузить JavaScript (JS) в статическую отрисовку на стороне Blazor Web App сервера (статический SSR) и расширенную навигацию.
Некоторые приложения зависят от выполнения задач инициализации, относящихся JS к каждой странице. При использовании Blazorрасширенной функции навигации, которая позволяет пользователю избежать перезагрузки всей страницы, конкретная JS страница может не выполняться повторно, как ожидалось при каждом возникновении расширенной навигации страницы.
Чтобы избежать этой проблемы, мы не рекомендуем полагаться на элементы, относящиеся к странице <script>
, расположенные за пределами файла макета, примененного к компоненту. Вместо этого скрипты должны зарегистрировать afterWebStarted
JS инициализатор для выполнения логики инициализации и использовать прослушиватель событий (blazor.addEventListener("enhancedload", 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
), добавьте следующий модуль.
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);
}
Добавьте следующий 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). Пример см. в разделе "Включение создания QR-кода для приложений проверки подлинности TOTP" в ASP.NET Core Blazor Web App.
ASP.NET Core