ASP.NET Core Blazor JavaScript con rendering statico lato server (SSR statico)
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Importante
Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Questo articolo illustra come caricare JavaScript (JS) in un oggetto Blazor Web App con rendering statico lato server (SSR statico) e spostamento avanzato.
Alcune app dipendono JS da per eseguire attività di inizializzazione specifiche di ogni pagina. Quando si usa Blazorla funzionalità di spostamento avanzata, che consente all'utente di evitare di ricaricare l'intera pagina, è possibile che non JS venga eseguito di nuovo come previsto ogni volta che si verifica un spostamento di pagina avanzato.
Per evitare questo problema, non è consigliabile basarsi su elementi specifici <script>
della pagina posizionati all'esterno del file di layout applicato al componente. Gli script devono invece registrare un afterWebStarted
JS inizializzatore per eseguire la logica di inizializzazione e usare un listener di eventi per rilevare gli aggiornamenti delle pagine causati dalla navigazione potenziata.
Avvenimenti
Negli esempi di Event Listener seguenti, il segnaposto {CALLBACK}
è la funzione di callback.
L'avvio di navigazione avanzata (
enhancednavigationstart
) attiva un callback prima che si verifichi una navigazione avanzata.blazor.addEventListener("enhancednavigationstart", {CALLBACK});
L'endpoint di navigazione avanzata (
enhancednavigationend
) attiva un callback dopo una navigazione avanzata:blazor.addEventListener("enhancednavigationend", {CALLBACK});
Il caricamento avanzato della pagina di navigazione (
enhancedload
) attiva un callback ogni volta che la pagina viene aggiornata a causa di una navigazione migliorata, inclusi aggiornamenti di streaming:blazor.addEventListener("enhancedload", {CALLBACK});
Per evitare questo problema, non è consigliabile basarsi su elementi specifici <script>
della pagina posizionati all'esterno del file di layout applicato al componente. Gli script devono invece registrare un inizializzatore afterWebStarted
JS per eseguire la logica di inizializzazione e usare un ascoltatore di eventi per captare gli aggiornamenti delle pagine causati dalla navigazione migliorata.
blazor.addEventListener("enhancedload", {CALLBACK});
Nell'esempio precedente il segnaposto {CALLBACK}
è la funzione di callback.
Esempio di script di caricamento pagina avanzato
Nell'esempio seguente viene illustrato un modo per configurare JS il codice da eseguire quando viene inizialmente caricato o aggiornato una pagina sottoposta a rendering statico con navigazione avanzata.
L'esempio di componente seguente PageWithScript
è un componente nell'app che richiede l'esecuzione di script con SSR statico e navigazione avanzata. L'esempio di componente seguente include un PageScript
componente di una libreria di Razor classi (RCL) aggiunta alla soluzione più avanti in questo articolo.
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 AppIn aggiungere il file collocato JS seguente:
-
onLoad
viene chiamato quando lo script viene aggiunto alla pagina. -
onUpdate
viene chiamato quando lo script esiste ancora nella pagina dopo un aggiornamento avanzato. -
onDispose
viene chiamato quando lo script viene rimosso dalla pagina dopo un aggiornamento avanzato.
Components/Pages/PageWithScript.razor.js
:
export function onLoad() {
console.log('Loaded');
}
export function onUpdate() {
console.log('Updated');
}
export function onDispose() {
console.log('Disposed');
}
In una libreria di classi Razor (RCL) (l'esempio RCL è denominato BlazorPageScript
), aggiungere il seguente modulo, che è un inizializzatore 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);
}
Non aggiungere un tag <script>
al componente radice dell'app, in genere il App
componente, per BlazorPageScript.lib.module.js
perché il modulo in questo caso è un inizializzatore JS (afterWebStarted
).
JS gli inizializzatori vengono rilevati e caricati automaticamente dal framework Blazor.
Nell'RCL aggiungere il componente seguente PageScript
.
PageScript.razor
:
<page-script src="@Src"></page-script>
@code {
[Parameter]
[EditorRequired]
public string Src { get; set; } = default!;
}
Il PageScript
componente funziona normalmente nel livello superiore di una pagina.
Se si inserisce il PageScript
componente nel layout di un'app (ad esempio , MainLayout.razor
), che genera una condivisione PageScript
tra le pagine che usano il layout, il componente viene eseguito onLoad
solo dopo un ricaricamento completo della pagina e onUpdate
quando si verifica un aggiornamento di pagina avanzato, inclusa la navigazione avanzata.
Per riutilizzare lo stesso modulo tra le pagine, ma richiamare i onLoad
callback e onDispose
in ogni modifica della pagina, aggiungere una stringa di query alla fine dello script in modo che venga riconosciuta come un modulo diverso. Un'app potrebbe adottare la convenzione di usare il nome del componente come valore della stringa di query. Nell'esempio seguente la stringa di query è "counter
" perché questo PageScript
riferimento al componente viene inserito in un Counter
componente. Si tratta semplicemente di un suggerimento ed è possibile usare qualsiasi schema di stringa di query preferito.
<PageScript Src="./Components/Pages/PageWithScript.razor.js?counter" />
Per monitorare le modifiche in elementi DOM specifici, usare il MutationObserver
modello in JS nel client. Per altre informazioni, vedere ASP.NET Core JavaScript interoperabilità (interoperabilità).For more information, see ASP.NET Core Blazor JavaScript interoperability (JS interop).
Implementazione senza usare un RCL
L'approccio descritto in questo articolo può essere implementato direttamente in un Blazor Web App senza usare una libreria di classi Razor (RCL) spostando gli asset dell'RCL nell'app. Tuttavia, l'uso di un RCL è utile perché l'RCL può essere inserito in un pacchetto NuGet per l'utilizzo da parte di Blazor app in un'organizzazione.
Se sposti gli asset in un Blazor Web App, assicurati di rinominare il modulo (BlazorPageScript.lib.module.js
) in modo che corrisponda all'applicazione secondo le regole di nomenclatura dei file per gli inizializzatori JS. Se il file non è denominato correttamente, Blazor non è in grado di rilevare e caricare il modulo e l'evento afterWebStarted
non viene eseguito automaticamente all'avvio dell'app.