Sdílet prostřednictvím


ASP.NET Core Blazor JavaScript se statickým vykreslováním na straně serveru (statické SSR)

Tento článek vysvětluje, jak načíst JavaScript (JS) do Blazor Web App vykreslování na straně statického serveru (static SSR) a vylepšenou navigaci.

Některé aplikace závisí na JS provádění inicializačních úloh, které jsou specifické pro každou stránku. Pokud používáte Blazorfunkci rozšířené navigace, která uživateli umožňuje vyhnout se opětovnému načtení celé stránky, nemusí být znovu spuštěna podle JS očekávání pokaždé, když dojde k rozšířené navigaci na stránce.

Abychom se tomuto problému vyhnuli, nedoporučujeme spoléhat se na prvky specifické pro <script> stránku umístěné mimo soubor rozložení použitý pro danou komponentu. Místo toho by skripty měly zaregistrovat afterWebStartedJS inicializátor pro provádění logiky inicializace a používat naslouchací proces událostí (blazor.addEventListener("enhancedload", callback)) k naslouchání aktualizacím stránek způsobeným vylepšenou navigací.

Následující příklad ukazuje jeden ze způsobů, jak nakonfigurovat JS kód, který se má spustit, když je na začátku načtena nebo aktualizována staticky vykreslená stránka s vylepšenou navigaci.

Následující PageWithScript příklad komponenty je komponenta v aplikaci, která vyžaduje, aby se skripty spouštěly se statickým prostředím SSR a vylepšenou navigaci. Následující příklad komponenty obsahuje komponentu PageScript Razor z knihovny tříd (RCL), která je přidána do řešení dále v tomto článku.

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.

Do pole Blazor Web Apppřidejte následující kompletovaný JS soubor:

  • onLoad je volána při přidání skriptu na stránku.
  • onUpdate je volána, pokud skript stále existuje na stránce po rozšířené aktualizaci.
  • onDispose je volána při odebrání skriptu ze stránky po rozšířené aktualizaci.

Components/Pages/PageWithScript.razor.js:

export function onLoad() {
  console.log('Loaded');
}

export function onUpdate() {
  console.log('Updated');
}

export function onDispose() {
  console.log('Disposed');
}

V knihovně Razor tříd (RCL) (příklad RCL je pojmenován BlazorPageScript) přidejte následující modul.

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);
}

Do seznamu RCL přidejte následující PageScript komponentu.

PageScript.razor:

<page-script src="@Src"></page-script>

@code {
    [Parameter]
    [EditorRequired]
    public string Src { get; set; } = default!;
}

Komponenta PageScript funguje normálně na nejvyšší úrovni stránky.

Pokud komponentu PageScript umístíte do rozložení aplikace (například MainLayout.razor), což vede ke sdílení PageScript mezi stránkami, které toto rozložení používají, pak se komponenta spustí onLoad až po opětovném načtení celé stránky a onUpdate při jakékoli rozšířené aktualizaci stránky, včetně rozšířené navigace.

Pokud chcete použít stejný modul mezi stránkami, ale při onLoad každé změně stránky se vyvolá a onDispose zpětná volání, připojte na konec skriptu řetězec dotazu, aby byl rozpoznán jako jiný modul. Aplikace může přijmout konvenci použití názvu komponenty jako řetězcové hodnoty dotazu. V následujícím příkladu je řetězec dotazu "counter", protože tento PageScript odkaz na komponentu Counter je umístěn. Jedná se pouze o návrh a můžete použít libovolné schéma řetězce dotazu, které dáváte přednost.

<PageScript Src="./Components/Pages/PageWithScript.razor.js?counter" />

Pokud chcete monitorovat změny v konkrétních prvčtech MODELU DOM, použijte MutationObserver vzor v JS klientovi. Další informace najdete v tématu ASP.NET Interoperabilita Core Blazor JavaScriptu (JSinteroperabilita).

Příklad implementace bez použití seznamu RCL

Přístup popsaný v tomto článku lze implementovat přímo v Blazor Web App bez použití Razor knihovny tříd (RCL). Příklad najdete v tématu Povolení generování kódu QR pro ověřovací aplikace TOTP v ASP.NET Core Blazor Web App.