Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Observação
Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão do .NET 10 deste artigo.
Este artigo explica como carregar JavaScript (JS) em um Blazor Web App com SSR estática (renderização estática no servidor) e navegação aprimorada.
Alguns aplicativos dependem de JS para executar tarefas de inicialização específicas para cada página. Ao usar o recurso de navegação aprimorada de Blazor, que permite ao usuário evitar recarregar a página inteira, o JS específico da página pode não ser executado novamente como esperado sempre que ocorrer uma navegação de página aprimorada.
Para evitar esse problema, não recomendamos confiar em elementos <script> específicos da página colocados fora do arquivo de layout aplicado ao componente. Em vez disso, os scripts devem registrar um afterWebStartedJS inicializador para executar a lógica de inicialização e usar um ouvinte de eventos para escutar atualizações de página causadas pela navegação aprimorada.
Eventos
Nos exemplos de ouvinte de eventos a seguir, o {CALLBACK} espaço reservado é a função de retorno de chamada.
O início de navegação aprimorado (
enhancednavigationstart) aciona um retorno de chamada antes que o processo de navegação aprimorado ocorra:blazor.addEventListener("enhancednavigationstart", {CALLBACK});O final de navegação aprimorada (
enhancednavigationend) dispara um retorno de chamada depois que ocorre uma navegação aprimorada:blazor.addEventListener("enhancednavigationend", {CALLBACK});O carregamento da página de navegação aprimorada (
enhancedload) aciona um retorno de chamada sempre que a página é atualizada devido a uma navegação aprimorada, incluindo atualizações de streaming:blazor.addEventListener("enhancedload", {CALLBACK});
Para evitar esse problema, não recomendamos confiar em elementos <script> específicos da página colocados fora do arquivo de layout aplicado ao componente. Em vez disso, os scripts devem registrar um afterWebStartedJS inicializador para executar a lógica de inicialização e usar um ouvinte de eventos para escutar atualizações de página causadas pela navegação aprimorada:
blazor.addEventListener("enhancedload", {CALLBACK});
No exemplo anterior, o espaço reservado {CALLBACK} é a função retorno de chamada.
Exemplo de script de carregamento de página aprimorado
O exemplo a seguir demonstra uma maneira de configurar o código JS para ser executado quando uma página renderizada estaticamente com navegação aprimorada for inicialmente carregada ou atualizada.
O exemplo de componente PageWithScript a seguir é um componente no aplicativo que exige que os scripts sejam executados com SSR estático e navegação aprimorada. O exemplo de componente a seguir inclui um componente PageScript de uma RCL (biblioteca de classes) Razor que é adicionado à solução mais adiante neste artigo.
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.
No Blazor Web App, adicione o seguinte arquivo JS associado:
-
onLoadé chamado quando o script é adicionado à página. -
onUpdateé chamado quando o script ainda existe na página após uma atualização aprimorada. -
onDisposeé chamado quando o script é removido da página após uma atualização aprimorada.
Components/Pages/PageWithScript.razor.js:
export function onLoad() {
console.log('Loaded');
}
export function onUpdate() {
console.log('Updated');
}
export function onDispose() {
console.log('Disposed');
}
Em uma Biblioteca de classes Razor (RLC) (o exemplo de RCL é nomeado BlazorPageScript), adicione o seguinte módulo, que é um inicializador 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);
}
Não adicione uma tag <script> ao componente raiz do aplicativo, normalmente o componente App, para BlazorPageScript.lib.module.js porque o módulo nesse caso é um inicializador JS (afterWebStarted). Inicializadores JS são detectados e carregados automaticamente pela estrutura Blazor.
Na RCL, adicione o componente PageScript a seguir.
PageScript.razor:
<page-script src="@Src"></page-script>
@code {
[Parameter]
[EditorRequired]
public string Src { get; set; } = default!;
}
O componente PageScript funciona normalmente no nível superior de uma página.
Se você colocar o componente PageScript em um layout do aplicativo (por exemplo, MainLayout.razor), o que resultará em um PageScript compartilhado entre as páginas que usam o layout, o componente só executará o onLoad após um recarregamento total da página e o onUpdate quando ocorrer qualquer atualização de página aprimorada, incluindo navegação aprimorada.
Para reutilizar o mesmo módulo entre as páginas, mas ter os retornos de chamada onLoad e onDispose invocados em cada alteração de página, acrescente uma string de consulta ao final do script para que ele seja reconhecido como um módulo diferente. Um aplicativo pode adotar a convenção de usar o nome do componente como o valor da string de consulta. No exemplo a seguir, a string de consulta é "counter" porque essa referência de componente PageScript é colocada em um componente Counter. Essa é apenas uma sugestão, e você pode usar qualquer esquema de string de consulta que preferir.
<PageScript Src="./Components/Pages/PageWithScript.razor.js?counter" />
Para monitorar alterações em elementos específicos do DOM, use o padrão MutationObserver no JS no cliente. Para obter mais informações, confira Interoperabilidade ASP.NET Core Blazor JavaScript (interoperabilidade JS).
Implementação sem usar uma RCL
A abordagem descrita neste artigo pode ser implementada diretamente em um Blazor Web App sem usar uma RCL (biblioteca de classes Razor) movendo os ativos da RCL para o aplicativo. No entanto, o uso de uma RCL é conveniente porque a RCL pode ser empacotada em um pacote NuGet para consumo por aplicativos Blazor em uma organização.
Se você mover os ativos para um Blazor Web App, renomeie o módulo (BlazorPageScript.lib.module.js) para corresponder ao aplicativo de acordo com as regras de nomenclatura de arquivo para inicializadores JS. Se o arquivo não for nomeado corretamente, Blazor não poderá detectar e carregar o módulo e o evento afterWebStarted não será executado automaticamente quando o aplicativo for iniciado.