ASP.NET Core Blazor JavaScript ze statycznym renderowaniem po stronie serwera (statyczne SSR)
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
W tym artykule wyjaśniono, jak załadować kod JavaScript (JS) w programie Blazor Web App ze statycznym renderowaniem po stronie serwera (static SSR) i rozszerzonymi nawigacjami.
Niektóre aplikacje zależą od JS wykonywania zadań inicjowania specyficznych dla każdej strony. W przypadku korzystania z Blazorrozszerzonej funkcji nawigacji, która pozwala użytkownikowi uniknąć ponownego ładowania całej strony, szczegółowe informacje dotyczące JS strony mogą nie być wykonywane ponownie zgodnie z oczekiwaniami za każdym razem, gdy wystąpi ulepszona nawigacja po stronie.
Aby uniknąć tego problemu, nie zalecamy polegania na elementach specyficznych dla <script>
strony umieszczonych poza plikiem układu zastosowanym do składnika. Zamiast tego skrypty powinny zarejestrować inicjalizator afterWebStarted
JS, aby wykonać logikę inicjowania, i użyć nasłuchiwacza zdarzeń do nasłuchiwania aktualizacji stron wynikających z ulepszonej nawigacji.
Zdarzenia
W poniższych przykładach odbiornika zdarzeń symbol zastępczy {CALLBACK}
jest funkcją wywołania zwrotnego.
Rozszerzony start nawigacji (
enhancednavigationstart
) wyzwala wywołanie zwrotne przed wykonaniem rozszerzonej nawigacji:blazor.addEventListener("enhancednavigationstart", {CALLBACK});
Rozszerzony koniec nawigacji (
enhancednavigationend
) wyzwala wywołanie zwrotne po wystąpieniu rozszerzonej nawigacji:blazor.addEventListener("enhancednavigationend", {CALLBACK});
Ulepszone ładowanie strony nawigacyjnej (
enhancedload
) wyzwala wywołanie zwrotne przy każdej aktualizacji strony z powodu ulepszonej nawigacji, w tym aktualizacje strumieniowe:blazor.addEventListener("enhancedload", {CALLBACK});
Aby uniknąć tego problemu, nie zalecamy polegania na elementach specyficznych dla <script>
strony umieszczonych poza plikiem układu zastosowanym do składnika. Zamiast tego skrypty powinny zarejestrować inicjator afterWebStarted
JS do wykonania logiki inicjowania i użyć odbiornika zdarzeń do nasłuchiwania aktualizacji stron spowodowanych przez rozszerzoną nawigację:
blazor.addEventListener("enhancedload", {CALLBACK});
W poprzednim przykładzie symbol zastępczy {CALLBACK}
jest funkcją wywołania zwrotnego.
Przykład rozszerzonego skryptu ładowania strony
W poniższym przykładzie pokazano jeden ze sposobów konfigurowania JS kodu do uruchomienia, gdy statycznie renderowana strona z rozszerzonym nawigacją jest początkowo ładowana lub aktualizowana.
Poniższy PageWithScript
przykładowy składnik to składnik w aplikacji, który wymaga uruchamiania skryptów przy użyciu statycznego przewodnika SSR i rozszerzonej nawigacji. Poniższy przykład składnika zawiera PageScript
składnik z Razor biblioteki klas (RCL), który jest dodawany do rozwiązania w dalszej części tego artykułu.
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.
W pliku Blazor Web Appdodaj następujący collocated JS plik:
-
onLoad
jest wywoływany po dodaniu skryptu do strony. -
onUpdate
jest wywoływany, gdy skrypt nadal istnieje na stronie po rozszerzonej aktualizacji. -
onDispose
jest wywoływany po usunięciu skryptu ze strony po rozszerzonej aktualizacji.
Components/Pages/PageWithScript.razor.js
:
export function onLoad() {
console.log('Loaded');
}
export function onUpdate() {
console.log('Updated');
}
export function onDispose() {
console.log('Disposed');
}
W Razor Class Library (RCL) (przykładowa lista RCL ma nazwę BlazorPageScript
), dodaj następujący moduł, który jest inicjatorem 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);
}
Nie dodawaj tagu <script>
do głównego komponentu aplikacji, zazwyczaj komponentu App
, BlazorPageScript.lib.module.js
ponieważ moduł w tym przypadku jest inicjalizatorem JS (afterWebStarted
).
JS inicjatory są wykrywane i ładowane automatycznie przez platformę Blazor.
Na liście RCL dodaj następujący PageScript
składnik.
PageScript.razor
:
<page-script src="@Src"></page-script>
@code {
[Parameter]
[EditorRequired]
public string Src { get; set; } = default!;
}
Składnik PageScript
działa normalnie na najwyższym poziomie strony.
Jeśli umieścisz PageScript
składnik w układzie aplikacji (na przykład MainLayout.razor
), co spowoduje udostępnienie PageScript
go między stronami korzystającymi z układu, składnik jest uruchamiany onLoad
tylko po ponownym załadowaniu pełnej strony i onUpdate
w przypadku wystąpienia dowolnej rozszerzonej aktualizacji strony, w tym rozszerzonej nawigacji.
Aby ponownie użyć tego samego modułu między stronami, ale wywołania onLoad
zwrotne i onDispose
są wywoływane na każdej stronie, dołącz ciąg zapytania na końcu skryptu, aby był rozpoznawany jako inny moduł. Aplikacja może przyjąć konwencję używania nazwy składnika jako wartości ciągu zapytania. W poniższym przykładzie ciąg zapytania to "counter
", ponieważ odwołanie do tego PageScript
składnika jest umieszczone w składniku Counter
. Jest to tylko sugestia i można użyć dowolnego preferowanego schematu ciągów zapytania.
<PageScript Src="./Components/Pages/PageWithScript.razor.js?counter" />
Aby monitorować zmiany w określonych elementach DOM, należy użyć MutationObserver
wzorca w JS kliencie. Aby uzyskać więcej informacji, zobacz ASP.NET Core Blazor JavaScript interoperability (JS interop).
Implementacja bez użycia RCL
Podejście opisane w tym artykule można zaimplementować bezpośrednio w Blazor Web App, przenosząc zasoby RCL bezpośrednio do aplikacji, zamiast używać biblioteki klas Razor (RCL). Jednak użycie listy RCL jest wygodne, ponieważ listę RCL można spakować do pakietu NuGet do użycia przez aplikacje Blazor w całej organizacji.
Jeśli przeniesiesz zasoby do Blazor Web App, pamiętaj o zmianie nazwy modułu (BlazorPageScript.lib.module.js
), aby odpowiadał aplikacji zgodnie z regułami nazewnictwa plików dla inicjatorów JS. Jeśli plik nie jest poprawnie nazwany, Blazor nie może wykryć i załadować modułu, a zdarzenie afterWebStarted
nie zostanie wykonane automatycznie po uruchomieniu aplikacji.