Heim >Web-Frontend >CSS-Tutorial >Ein Ansatz zum faulen Laden benutzerdefinierter Elemente

Ein Ansatz zum faulen Laden benutzerdefinierter Elemente

Joseph Gordon-Levitt
Joseph Gordon-LevittOriginal
2025-03-09 11:39:10216Durchsuche

An Approach to Lazy Loading Custom Elements

In diesem Artikel wird eine faule Lademethode für benutzerdefinierte Elemente zur Verbesserung der Webseitenleistung untersucht. Diese Methode wurde von den Experimenten der Kollegen inspiriert, und ihre Kernidee bestand darin, den entsprechenden Implementierungscode automatisch zu laden, nachdem benutzerdefinierte Elemente dem DOM hinzugefügt wurden.

Normalerweise besteht kein so komplexer fauler Lademechanismus, aber die in diesem Artikel beschriebenen Techniken sind für bestimmte Szenarien immer noch wertvoll.

Um die Konsistenz aufrechtzuerhalten, ist der faule Lader selbst auch als benutzerdefiniertes Element für eine einfache Konfiguration über HTML ausgelegt. Zunächst müssen wir ungelöste benutzerdefinierte Elemente nach und nach identifizieren:

class AutoLoader extends HTMLElement {
  connectedCallback() {
    const scope = this.parentNode;
    this.discover(scope);
  }
}
customElements.define("ce-autoloader", AutoLoader);

Angenommen, wir haben dieses Modul vorgeladen (idealerweise mit einer asynchronen Methode), können wir das Dokument <ce-autoloader></ce-autoloader> Element hinzufügen. Dadurch wird der Suchprozess sofort für alle untergeordneten Elemente gestartet, die das Stammelement bilden. Durch Hinzufügen von <ce-autoloader></ce-autoloader> zum entsprechenden Containerelement können Sie den Umfang der Suche in den Unterbaum des Dokuments einschränken und sogar mehrere Instanzen in verschiedenen Teilbäumen verwenden.

Als nächstes müssen wir die discover -Methode (als Teil der obigen Klasse) implementieren: AutoLoader

discover(scope) {
  const candidates = [scope, ...scope.querySelectorAll("*")];
  for (const el of candidates) {
    const tag = el.localName;
    if (tag.includes("-") && !customElements.get(tag)) {
      this.load(tag);
    }
  }
}
Dieser Code überprüft nach dem Stammelement und all seinen Nachkommen (*). Wenn das Element ein benutzerdefiniertes Element ist (ein beilagerter Etikett), aber noch nicht aktualisiert wurde, versuchen Sie, die entsprechende Definition zu laden. Diese Methode kann eine große Menge an DOM -Abfrageressourcen einnehmen, daher muss sie mit Vorsicht behandelt werden. Wir können die Last am Haupt -Thread reduzieren, indem wir die Ausführung verzögern:

connectedCallback() {
  const scope = this.parentNode;
  requestIdleCallback(() => {
    this.discover(scope);
  });
}

Nicht alle Browser unterstützen es, Sie können requestIdleCallback als Sicherungsplan verwenden: requestAnimationFrame

const defer = window.requestIdleCallback || requestAnimationFrame;

class AutoLoader extends HTMLElement {
  connectedCallback() {
    const scope = this.parentNode;
    defer(() => {
      this.discover(scope);
    });
  }
  // ...
}
Jetzt können wir die

-Methode implementieren, die load Elemente dynamisch injizieren: <script></script>

load(tag) {
  const el = document.createElement("script");
  const res = new Promise((resolve, reject) => {
    el.addEventListener("load", () => resolve(null));
    el.addEventListener("error", () => reject(new Error("未能找到自定义元素定义")));
  });
  el.src = this.elementURL(tag);
  document.head.appendChild(el);
  return res;
}

elementURL(tag) {
  return `${this.rootDir}/${tag}.js`;
}
Bitte beachten Sie die hartcodierte Konvention in

. In der URL des elementURL Attributs geht davon aus, dass ein Verzeichnis, das alle benutzerdefinierten Elementdefinitionen enthält (z. B. src<my-widget></my-widget>). Wir können komplexere Strategien anwenden, aber dies reicht für unsere Zwecke. Delegieren Sie diese URL an eine separate Methode, um bei Bedarf die projektspezifische Unterklasse zu ermöglichen: /components/my-widget.js

class FancyLoader extends AutoLoader {
  elementURL(tag) {
    // 自定义逻辑
  }
}
In beiden Fällen verlassen wir uns auf

. Dies ist die zuvor erwähnte Konfigurierbarkeit. Fügen wir einen entsprechenden Getter hinzu: this.rootDir

get rootDir() {
  const uri = this.getAttribute("root-dir");
  if (!uri) {
    throw new Error("无法自动加载自定义元素:缺少`root-dir`属性");
  }
  return uri.endsWith("/") ? uri.substring(0, uri.length - 1) : uri;
}
Wir müssen

nicht verwenden, da die Aktualisierung der observedAttributes -Mobilie zur Laufzeit unnötig erscheint. root-dir

Jetzt können wir das Elementverzeichnis konfigurieren (und müssen):

. <ce-autoloader root-dir="/components"></ce-autoloader>

damit funktioniert unser Autoloader. Es funktioniert jedoch nur für Elemente, die bereits existieren, wenn der Autoloader initialisiert wird. Möglicherweise müssen wir auch dynamisch hinzugefügte Elemente berücksichtigen. Hier kommt

ins Spiel: MutationObserver

class AutoLoader extends HTMLElement {
  connectedCallback() {
    const scope = this.parentNode;
    this.discover(scope);
  }
}
customElements.define("ce-autoloader", AutoLoader);

Auf diese Weise benachrichtigt uns der Browser, wenn ein neues Element im DOM erscheint (genauer gesagt unser entsprechendes Subtree), und wir verwenden es dann, um den Nachschlagprozess neu zu starten.

Unser Autoloader ist jetzt vollständig verwendbar. Zukünftige Verbesserungen können die Untersuchung der potenziellen Wettbewerbsbedingungen und der Optimierung umfassen. Aber für die meisten Szenarien reicht das aus. Wenn Sie einen anderen Ansatz haben, lassen Sie es mich bitte in den Kommentaren wissen und wir können miteinander kommunizieren!

Das obige ist der detaillierte Inhalt vonEin Ansatz zum faulen Laden benutzerdefinierter Elemente. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn