Kontextbewusste Webkomponenten sind einfacher als Sie denken | CSS-Tricks

Ein weiterer Aspekt von Webkomponenten, über den wir noch nicht gesprochen haben, ist, dass eine JavaScript-Funktion immer dann aufgerufen wird, wenn eine Webkomponente zu einer Seite hinzugefügt oder von ihr entfernt wird. Diese Lebenszyklus-Callbacks können für viele Dinge verwendet werden, einschließlich der Sensibilisierung eines Elements für seinen Kontext.

Artikelserie

Die vier Lebenszyklus-Callbacks von Webkomponenten

Es gibt vier Lifecycle-Callbacks die mit Webkomponenten verwendet werden können:

  • connectedCallback: Dieser Rückruf wird ausgelöst, wenn das benutzerdefinierte Element vorhanden ist angebracht zum Element.
  • disconnectedCallback: Dieser Rückruf wird ausgelöst, wenn das Element ist ENTFERNT aus dem Dokument.
  • adoptedCallback: Dieser Rückruf wird ausgelöst, wenn das Element ist hinzugefügt zu einem neuen Dokument.
  • attributeChangedCallback: Dieser Rückruf wird ausgelöst, wenn ein Attribut geändert, hinzugefügt oder entfernt wird, solange dieses Attribut beachtet wird.

Sehen wir uns diese in Aktion an.

Unsere postapokalyptische Personenkomponente

Zwei Renderings der Webkomponente nebeneinander, links ist ein Mensch und rechts ein Zombie.

Wir beginnen mit der Erstellung einer Webkomponente namens <postapocalyptic-person>. Jede Person nach der Apokalypse ist entweder ein Mensch oder ein Zombie und wir werden anhand einer Klasse wissen, welcher von beiden .human oder .zombie — das auf das übergeordnete Element von angewendet wird <postapocalyptic-person> Komponente. Wir werden (noch) nichts Besonderes damit machen, aber wir werden a hinzufügen shadowRoot können wir verwenden, um ein entsprechendes Bild basierend auf dieser Klassifizierung anzuhängen.

customElements.define(
  "postapocalyptic-person",
  class extends HTMLElement {
    constructor() {
      super();
      const shadowRoot = this.attachShadow({ mode: "open" });
    }
}

Unser HTML sieht so aus:

<div class="humans">
  <postapocalyptic-person></postapocalyptic-person>
</div>
<div class="zombies">
  <postapocalyptic-person></postapocalyptic-person>
</div>

Einfügen von Personen mit connectedCallback

Wenn ein <postapocalyptic-person> auf der Seite geladen wird, die connectedCallback() Funktion aufgerufen wird.

connectedCallback() {
  let image = document.createElement("img");
  if (this.parentNode.classList.contains("humans")) {
    image.src = "https://assets.codepen.io/1804713/lady.png";
    this.shadowRoot.appendChild(image);
  } else if (this.parentNode.classList.contains("zombies")) {
    image.src = "https://assets.codepen.io/1804713/ladyz.png";
    this.shadowRoot.appendChild(image);
  }
}

Dadurch wird sichergestellt, dass ein Bild eines Menschen ausgegeben wird, wenn die <postapocalyptic-person> ein Mensch ist, und ein Zombiebild, wenn die Komponente ein Zombie ist.

Arbeiten Sie vorsichtig damit connectedCallback. Es läuft öfter, als Sie vielleicht denken, und feuert jedes Mal, wenn das Element bewegt wird, und könnte (verblüffenderweise) sogar laufen nach der Knoten ist nicht mehr verbunden – was zu hohen Leistungseinbußen führen kann. Sie können verwenden this.isConnected um zu wissen, ob das Element verbunden ist oder nicht.

Personen zählen mit connectedCallback() wenn sie hinzugefügt werden

Lassen Sie uns etwas komplexer werden, indem wir der Mischung ein paar Schaltflächen hinzufügen. Man wird a hinzufügen <postapocalyptic-person>, wobei ein „Coin Flip“-Ansatz verwendet wird, um zu entscheiden, ob es sich um einen Menschen oder einen Zombie handelt. Die andere Taste bewirkt das Gegenteil und entfernt a <postapocalyptic-person> zufällig. Wir werden verfolgen, wie viele Menschen und Zombies in Sichtweite sind, wenn wir schon dabei sind.

<div class="btns">
  <button id="addbtn">Add Person</button>
  <button id="rmvbtn">Remove Person</button> 
  <span class="counts">
    Humans: <span id="human-count">0</span> 
    Zombies: <span id="zombie-count">0</span>
  </span>
</div>

Hier ist, was unsere Schaltflächen tun werden:

let zombienest = document.querySelector(".zombies"),
  humancamp = document.querySelector(".humans");

document.getElementById("addbtn").addEventListener("click", function () {
  // Flips a "coin" and adds either a zombie or a human
  if (Math.random() > 0.5) {
    zombienest.appendChild(document.createElement("postapocalyptic-person"));
  } else {
    humancamp.appendChild(document.createElement("postapocalyptic-person"));
  }
});
document.getElementById("rmvbtn").addEventListener("click", function () {
  // Flips a "coin" and removes either a zombie or a human
  // A console message is logged if no more are available to remove.
  if (Math.random() > 0.5) {
    if (zombienest.lastElementChild) {
      zombienest.lastElementChild.remove();
    } else {
      console.log("No more zombies to remove");
    }
  } else {
    if (humancamp.lastElementChild) {
      humancamp.lastElementChild.remove();
    } else {
      console.log("No more humans to remove");
    }
  }
});

Hier ist der Code drin connectedCallback() das zählt die Menschen und Zombies, wenn sie hinzugefügt werden:

connectedCallback() {
  let image = document.createElement("img");
  if (this.parentNode.classList.contains("humans")) {
    image.src = "https://assets.codepen.io/1804713/lady.png";
    this.shadowRoot.appendChild(image);
    // Get the existing human count.
    let humancount = document.getElementById("human-count");
    // Increment it
    humancount.innerHTML = parseInt(humancount.textContent) + 1;
  } else if (this.parentNode.classList.contains("zombies")) {
    image.src = "https://assets.codepen.io/1804713/ladyz.png";
    this.shadowRoot.appendChild(image);
    // Get the existing zombie count.
    let zombiecount = document.getElementById("zombie-count");
    // Increment it
    zombiecount.innerHTML = parseInt(zombiecount.textContent) + 1;
  }
}

Die Aktualisierung zählt mit disconnectedCallback

Als nächstes können wir verwenden disconnectedCallback() um die Zahl zu verringern, wenn Menschen und Zombies entfernt werden. Allerdings können wir die Klasse des übergeordneten Elements nicht überprüfen, da das übergeordnete Element mit der entsprechenden Klasse zu der Zeit bereits weg ist disconnectedCallback wird genannt. Wir könnten ein Attribut für das Element festlegen oder dem Objekt eine Eigenschaft hinzufügen, aber da das Bild src -Attribut bereits durch sein übergeordnetes Element bestimmt wird, können wir dies als Proxy verwenden, um zu wissen, ob die zu entfernende Webkomponente ein Mensch oder ein Zombie ist.

disconnectedCallback() {
  let image = this.shadowRoot.querySelector('img');
  // Test for the human image
  if (image.src == "https://assets.codepen.io/1804713/lady.png") {
    let humancount = document.getElementById("human-count");
    humancount.innerHTML = parseInt(humancount.textContent) - 1; // Decrement count
  // Test for the zombie image
  } else if (image.src == "https://assets.codepen.io/1804713/ladyz.png") {
    let zombiecount = document.getElementById("zombie-count");
    zombiecount.innerHTML = parseInt(zombiecount.textContent) - 1; // Decrement count
  }
}

Achtung Clowns!

Jetzt (und ich spreche hier natürlich aus Erfahrung) ist das einzige, was noch gruseliger ist als eine Horde Zombies, die auf Ihre Position stürmen, ein Clown – es braucht nur einen! Also, obwohl wir es bereits mit furchterregenden postapokalyptischen Zombies zu tun haben, fügen wir für noch mehr Horror die Möglichkeit hinzu, dass ein Clown die Szene betritt. Tatsächlich werden wir es so machen, dass die Möglichkeit besteht, dass jeder Mensch oder Zombie auf dem Bildschirm heimlich ein verkleideter Clown ist!

Ich nehme zurück, was ich vorhin gesagt habe: Ein einzelner Zombie-Clown ist gruseliger als selbst eine Gruppe „normaler“ Clowns. Nehmen wir an, wenn irgendeine Art von Clown gefunden wird – sei es Mensch oder Zombie –, trennen wir sie von der Menschen- und Zombiepopulation, indem wir sie zu einem ganz anderen Dokument schicken – an <iframe> Gefängnis, wenn Sie wollen. (Ich habe gehört, dass „Clowning“ noch ansteckender sein könnte als die Ansteckung durch Zombies.)

Und wenn wir einen mutmaßlichen Clown aus dem aktuellen Dokument in ein verschieben <iframe>, wird der ursprüngliche Knoten nicht zerstört und neu erstellt; vielmehr nimmt er den Knoten an und verbindet ihn, wobei er zuerst ruft adoptedCallback dann connectedCallback.

Wir brauchen nichts in der <iframe> Dokument außer einem Körper mit a .clowns Klasse. Solange sich dieses Dokument im iframe des Hauptdokuments befindet – nicht separat betrachtet – brauchen wir die nicht einmal <postapocalyptic-person> Instanziierungscode. Wir werden einen Raum für Menschen, einen anderen Raum für Zombies und ja, das Gefängnis der Clowns … ähm … <iframe> aus Spaß.

<div class="btns">
  <button id="addbtn">Add Person</button>
  <button id="jailbtn">Jail Potential Clown</button>
</div>
<div class="humans">
  <postapocalyptic-person></postapocalyptic-person>
</div>
<div class="zombies">
  <postapocalyptic-person></postapocalyptic-person>
</div>
<iframe class="clowniframeoffun” src="https://css-tricks.com/context-aware-web-components/adoptedCallback-iframe.html">
</iframe>

Unsere Schaltfläche „Person hinzufügen“ funktioniert genauso wie im letzten Beispiel: Sie wirft eine digitale Münze, um zufällig entweder einen Menschen oder einen Zombie einzufügen. Wenn wir auf die Schaltfläche „Potenzieller Gefängnisclown“ klicken, wird eine weitere Münze geworfen und nimmt entweder einen Zombie oder einen Menschen und übergibt sie an ihn <iframe> Gefängnis.

document.getElementById("jailbtn").addEventListener("click", function () {
  if (Math.random() > 0.5) {
    let human = humancamp.querySelector('postapocalyptic-person');
    if (human) {
      clowncollege.contentDocument.querySelector('body').appendChild(document.adoptNode(human));
    } else {
      console.log("No more potential clowns at the human camp");
    }
  } else {
    let zombie = zombienest.querySelector('postapocalyptic-person');
    if (zombie) {
      clowncollege.contentDocument.querySelector('body').appendChild(document.adoptNode(zombie));
    } else {
      console.log("No more potential clowns at the zombie nest");
    }
  }
});

Freizügige Clowns mit adoptedCallback

Im adoptedCallback Wir bestimmen anhand des entsprechenden Bildes, ob es sich bei dem Clown um einen Zombie-Menschen handelt, und ändern dann das Bild entsprechend. connectedCallback wird danach aufgerufen, aber wir haben nichts, was es tun muss, und was es tut, wird unsere Änderungen nicht beeinträchtigen. Also können wir es so lassen wie es ist.

adoptedCallback() {
  let image = this.shadowRoot.querySelector("img");
  if (this.parentNode.dataset.type == "clowns") {
    if (image.src.indexOf("lady.png") != -1) { 
      // Sometimes, the full URL path including the domain is saved in `image.src`.
      // Using `indexOf` allows us to skip the unnecessary bits. 
      image.src = "https://css-tricks.com/context-aware-web-components/ladyc.png";
      this.shadowRoot.appendChild(image);
    } else if (image.src.indexOf("ladyz.png") != -1) {
      image.src = "ladyzc.png";
      this.shadowRoot.appendChild(image);
    }
  }
}

Versteckte Clowns erkennen mit attributeChangedCallback

Endlich haben wir die attributeChangedCallback. Im Gegensatz zu den anderen drei Lebenszyklus-Callbacks müssen wir die Attribute unserer Webkomponente beobachten, damit der Callback ausgelöst wird. Wir können dies tun, indem wir an hinzufügen observedAttributes() -Funktion zur Klasse des benutzerdefinierten Elements hinzufügen und diese Funktion ein Array von Attributnamen zurückgeben lassen.

static get observedAttributes() {
  return [“attribute-name”];
}

Wenn sich dieses Attribut dann ändert – einschließlich Hinzufügen oder Entfernen – wird die attributeChangedCallback Feuer.

Nun müssen Sie sich bei Clowns Sorgen machen, dass einige der Menschen, die Sie kennen und lieben (oder diejenigen, die Sie kannten und liebten, bevor sie sich in Zombies verwandelten), heimlich verkleidete Clowns sein könnten. Ich habe einen Clown-Detektor eingerichtet, der eine Gruppe von Menschen und Zombies betrachtet, und wenn Sie auf die Schaltfläche „Clowns aufdecken“ klicken, wird der Detektor (durch vollständig wissenschaftliche und absolut vertrauenswürdige Mittel, die sind nicht basierend auf Zufallszahlen, die einen Index wählen) gelten data-clown="true" zum Bauteil. Und wenn dieses Attribut angewendet wird, attributeChangedCallback Feuer und aktualisiert das Bild der Komponente, um ihre clownesken Farben aufzudecken.

Ich sollte auch beachten, dass die attributeChangedCallback nimmt drei Parameter:

  • der Name des Attributs
  • der vorherige Wert des Attributs
  • der neue Wert des Attributs

Darüber hinaus können Sie mit dem Rückruf Änderungen basierend darauf vornehmen, wie stark sich das Attribut geändert hat, oder basierend auf dem Übergang zwischen zwei Zuständen.

Hier ist unsere attributeChangedCallback Code:

attributeChangedCallback(name, oldValue, newValue) {
  let image = this.shadowRoot.querySelector("img");
  // Ensures that `data-clown` was the attribute that changed,
  // that its value is true, and that it had an image in its `shadowRoot`
  if (name="data-clown" && this.dataset.clown && image) {
    // Setting and updating the counts of humans, zombies,
    // and clowns on the page
    let clowncount = document.getElementById("clown-count"),
    humancount = document.getElementById("human-count"),
    zombiecount = document.getElementById("zombie-count");
    if (image.src.indexOf("lady.png") != -1) {
      image.src = "https://assets.codepen.io/1804713/ladyc.png";
      this.shadowRoot.appendChild(image);
      // Update counts
      clowncount.innerHTML = parseInt(clowncount.textContent) + 1;
      humancount.innerHTML = parseInt(humancount.textContent) - 1;
    } else if (image.src.indexOf("ladyz.png") != -1) {
      image.src = "https://assets.codepen.io/1804713/ladyzc.png";
      this.shadowRoot.appendChild(image);
      // Update counts
      clowncount.innerHTML = parseInt(clowncount.textContent) + 1;
      zombiecount.innerHTML = parseInt(zombiecount.textContent) - 1;
    }
  }
}

Und da haben Sie es! Wir haben nicht nur herausgefunden, dass Callbacks von Webkomponenten und das Erstellen kontextbezogener benutzerdefinierter Elemente einfacher sind, als Sie vielleicht gedacht haben, sondern auch das Erkennen postapokalyptischer Clowns ist zwar erschreckend, aber auch einfacher als Sie dachten. Welche hinterhältigen, postapokalyptischen Clowns können Sie mit diesen Callback-Funktionen von Webkomponenten erkennen?

Published
Categorized as Marketing

By Nguyen Manh Cuong

Nguyen Manh Cuong is the author and founder of the nguyendiep blog. With over 14 years of experience in Online Marketing, he now runs a number of successful websites, and occasionally shares his experience & knowledge on this blog.

Leave a comment

Your email address will not be published. Required fields are marked *