Faul Laden von Bildern, die mit Vue.js Richtlinien und Kreuzung Beobachter

0
23

Wenn ich daran denke, web-performance, die erste Sache, die mir in den Sinn kommt ist, wie die Bilder sind in der Regel die letzten Elemente auf einer Seite angezeigt werden. Heute können Bilder eine wichtige Frage, wenn es zur Leistung kommt, das ist bedauerlich, da die Geschwindigkeit einer website lädt, hat direkte Auswirkungen auf die Benutzer wurden erfolgreich zu tun, was Sie kam auf der Seite zu tun (denken Sie Gespräch-Tarife).

Sehr vor kurzem, Rahul Nanwani schrieb eine umfangreiche Anleitung, faul laden von Bildern. Ich würde gerne über das gleiche Thema, aber aus einem anderen Ansatz: mit data-Attribute, die Kreuzung Beobachter und benutzerdefinierte Richtlinien Vue.js.

Was dieser im Grunde tun, ist uns erlauben, zu lösen, sind zwei Dinge:

  1. Speichern Sie die src von dem Bild, das wir laden wollen, ohne zu laden, es in den ersten Platz.
  2. Erkennen, wenn das Bild sichtbar wird und dem Benutzer auslösen der Anfrage zum laden der Bild.

Gleichen grundlegenden lazy loading-Konzept, sondern ein anderer Weg, um darüber zu gehen.

Ich habe ein Beispiel erstellt, basierend auf ein Beispiel beschrieben von Benjamin Taylor in seinem blog-post. Es enthält eine Liste mit zufälligen Artikeln jeweils mit einer kurzen Beschreibung, Bild und einem link zur Quelle des Artikels. Wir gehen durch den Prozess der Erstellung einer Komponente, die verantwortlich für die Anzeige, die Liste, so dass ein Artikel und verzögertes laden des Bildes für einen bestimmten Artikel.

Lasst uns faul! Oder zumindest brechen diese Komponenten runter, Stück für Stück.

Schritt 1: Erstellen der ImageItem Komponente in Vue

Beginnen Sie, indem Sie eine Komponente erstellen, die Ihnen zeigen, ein Bild (aber kein lazy loading beteiligten nur noch). Wir nennen diese Datei ImageItem.vue. In der Bauteil-Vorlage, die wir verwenden werden, Abbildung-tag, enthält unser image — das image-tag selbst erhalten die src-Attribut, das auf die Quell-URL für die Bilddatei.

<Vorlage>
<figure class=”image__ – wrapper”>
<img
class=”image__item”
:src=”Quelle”
alt=”random image”
>
</figure>
</template>

Im Skript-Abschnitt der Komponente erhalten wir die requisite-Quelle, die wir nutzen werden für das src-url von dem Bild, das wir anzeigen.

export default {
name: “ImageItem”,
Requisiten: {
Quelle: {
Typ: Zeichenfolge,
erforderlich: true
}
}
};

All dies ist völlig in Ordnung, und rendert das Bild wieder normal ist. Aber, wenn wir es hierbei belassen, das Bild wird geladen, sofort, ohne zu warten, für die gesamte Komponente zu Rendern. Das ist nicht das, was wir wollen, also lasst uns gehen Sie zum nächsten Schritt.

Schritt 2: Verhindern, dass das Bild geladen wird, wenn die Komponente erstellt wurde

Es klingt vielleicht ein wenig komisch, dass wir verhindern wollen, dass etwas geladen wird, wenn wir zeigen wollen, doch ist dies über das laden der es an der rechten Zeit, anstatt es zu blockieren, auf unbestimmte Zeit. Um zu verhindern, dass das Bild geladen wird, die wir benötigen, um loszuwerden, das src-Attribut vom img-tag. Aber, wir müssen noch lagern Sie es irgendwo, so dass wir Sie nutzen können, wenn wir es wollen. Ein guter Ort, um zu halten, dass die Informationen in einem data – Attribut. Diese erlauben es uns, Informationen zu speichern, auf standard -, semantische HTML-Elemente. In der Tat kann man sich bereits daran gewöhnt, mit Ihnen als JavaScript-Selektoren.

In diesem Fall, Sie sind eine perfekte Passform für unsere Bedürfnisse!

<!–ImageItem.vue–>
<Vorlage>
<figure class=”image__ – wrapper”>
<img
class=”image__item”
:data-url=”Quelle” // yay für data-Attribute!
alt=”random image”
>
</figure>
</template>

Mit, dass unser image nicht geladen, da gibt es keine Quell-URL zu ziehen.

Das ist ein guter Anfang, aber noch nicht ganz das, was wir wollen. Wir möchten, laden unser Bild, die nur unter bestimmten Bedingungen. Wir können verlangen, das Bild zu laden, durch den Austausch des src-Attribut mit der Bildquelle die URL immer in unserer data-url-Attribut. Das ist der einfache Teil. Die eigentliche Herausforderung ist, herauszufinden, wenn Sie zu ersetzen mit der eigentlichen Quelle.

Unser Ziel ist die pin die Last auf dem Bildschirm des Benutzers-Speicherort. Also, wenn der Benutzer scrollt zu einem Punkt, wo das Bild in Sicht kommt, das ist, wo es geladen wird.

Wie können wir erkennen, ob das Bild in der Ansicht oder nicht? Das ist unser Nächster Schritt.

Schritt 3: Erkennen, wenn das Bild für den Benutzer sichtbar ist

Haben Sie eventuell Erfahrung mit JavaScript, um zu bestimmen, wenn ein element ist nicht in Sicht. Vielleicht haben Sie auch Erfahrung Wicklung mit einigen knorrigen Schrift.

Zum Beispiel, können wir die Ereignisse und event-Handler zu erkennen, die die scroll-position-offset-Wert, element-Höhe, und die viewport-Höhe, dann berechnen, ob ein Bild in den Arbeitsbereich, oder nicht. Aber das hört sich schon Hammer, nicht wahr?

Aber es könnte noch schlimmer werden. Dies hat direkte Auswirkungen auf die Leistung. Diese Berechnungen würde gefeuert werden alle scroll-Ereignis. Noch schlimmer, stellen Sie sich vor ein paar Dutzend Bilder, die jeder für sich nachrechnen, ob es sichtbar ist oder nicht, auf jeden scroll-Ereignis. Wahnsinn!

Kreuzung Beobachter ist die Rettung! Dies bietet eine sehr effiziente Möglichkeit zu erkennen, ob ein element sichtbar ist in den viewport. Insbesondere können Sie konfigurieren, ein callback , der ausgelöst wird, wenn ein element — das sogenannte target — schneidet entweder das Gerät viewport oder einem angegebenen element.

Also, was wir tun müssen, um es zu nutzen? Ein paar Dinge:

  • erstellen Sie eine neue Kreuzung Beobachter
  • beobachten Sie das element, das wir wollen, lazy load für die Sichtbarkeit ändert
  • laden Sie das element, wenn das element in den viewport (durch ersetzen von src mit unseren Daten-url)
  • stoppen, gerade für die Sichtbarkeit von änderungen (unobserve) nachdem das laden abgeschlossen ist

Vue.js hat eigene Richtlinien zu wickeln, alle diese Funktionen zusammen, und verwenden Sie es, wenn wir es brauchen, so viele Male, wie wir es brauchen. Setzen, dass zu bedienen, ist unser Nächster Schritt.

Schritt 4: Erstellen Sie eine Vue benutzerdefinierte Richtlinie

Was ist eine benutzerdefinierte Richtlinie? Vue die Dokumentation beschreibt es als einen Weg, um low-level-DOM-Zugriff auf Elemente. Zum Beispiel ist die änderung eines Attributs eines bestimmten DOM-element, das in unserem Fall sein könnte, ändern Sie das src-Attribut eines img-Elements. Perfekt!

Wir werden diese brechen in einem moment, aber hier ist, was wir suchen, so weit als der code:

export default {
eingefügt: el => {
Funktion loadImage() {
const imageElement = Array.aus(el.Kinder).find(
el => el.nodeName === “IMG”
);
wenn (imageElement) {
imageElement.addEventListener(“load”, () => {
setTimeout(() => el.classList.add(“geladen”), 100);
});
imageElement.addEventListener(“Fehler”, () => console.log(“Fehler”));
imageElement.src = ” imageElement.dataset.url;
}
}

Funktion handleIntersect(Einträge, observer) {
Einträge.forEach(entry => {
if (Eintrag.isIntersecting) {
loadImage();
Beobachter.unobserve(el);
}
});
}

Funktion createObserver() {
const options = {
root: null,
Schwelle: “0”
};
const observer = new IntersectionObserver(handleIntersect, Optionen);
Beobachter.beobachten(el);
}
if (window[“IntersectionObserver”]) {
createObserver();
} else {
loadImage();
}
}
};

OK, befassen wir uns mit diesem Schritt-für-Schritt.

Die hook-Funktion ermöglicht uns Feuer eine benutzerdefinierte Logik in einem bestimmten moment eines gebundenen element Lebenszyklus. Wir verwenden die Haken eingefügt, weil es heißt, wenn das gebundene element eingefügt wurde, in seinen übergeordneten Knoten (dies garantiert die übergeordnete Knoten vorhanden ist). Da wollen wir beobachten, die Sichtbarkeit eines Elements im Vergleich zu Ihren Eltern (oder der Vorfahren), den wir verwenden müssen, dass die Haken.

export default {
eingefügt: el => {

}
}

Die loadImage-Funktion ist verantwortlich für das ersetzen der src-Wert mit dem data-url. In ihm haben wir Zugang zu unserem element (el), die ist, wo wir die Anwendung der Richtlinie. Wir extrahieren die img aus, dass element.

Als Nächstes überprüfen wir, ob das Bild existiert und, wenn es funktioniert, fügen wir einen listener, der ausgelöst wird, eine callback-Funktion, wenn der Ladevorgang beendet ist. Rückruf verantwortlich für das verstecken der spinner und das hinzufügen der animation (fade-in-Effekt), um das Bild über eine CSS-Klasse. Fügen wir auch einen zweiten listener, der aufgerufen wird, in dem Fall, dass die URL nicht geladen werden.

Schließlich ersetzen wir die src von unserem img-element mit der Quell-URL des Bildes und zeigen Sie es!

Funktion loadImage() {
const imageElement = Array.aus(el.Kinder).find(
el => el.nodeName === “IMG”
);
wenn (imageElement) {
imageElement.addEventListener(“load”, () => {
setTimeout(() => el.classList.add(“geladen”), 100);
});
imageElement.addEventListener(“Fehler”, () => console.log(“Fehler”));
imageElement.src = ” imageElement.dataset.url;
}
}

Wir nutzen Kreuzung Betrachters handleIntersect Funktion, die verantwortlich ist für das brennen loadImage, wenn bestimmte Bedingungen erfüllt sind. Speziell, es wird entlassen werden, wenn die Kreuzung Beobachter erkennt, dass das element tritt in den viewport oder einer übergeordneten Komponente element.

Die Funktion hat Zugriff auf Einträge, die ein array aller Elemente, die beobachtet werden, der Beobachter und der Beobachter selbst. Wir iterieren über die Einträge und überprüfen Sie, ob ein einzelner Eintrag wird sichtbar, um unsere Benutzer mit isIntersecting — und Feuer-der loadImage-Funktion, wenn es ist. Wenn das Bild angefordert wird, wir unobserve das element (entfernen Sie Sie aus dem observer ‘ s watch list), die verhindert, dass das Bild geladen wird, wieder. Und wieder. Und wieder. Und…

Funktion handleIntersect(Einträge, observer) {
Einträge.forEach(entry => {
if (Eintrag.isIntersecting) {
loadImage();
Beobachter.unobserve(el);
}
});
}

Das Letzte Stück ist die createObserver Funktion. Dieser Mann ist verantwortlich für die Erstellung unserer Kreuzung Beobachter und befestigen Sie es an unserem element. Die IntersectionObserver Konstruktor eine Rückruffunktion (unsere handleIntersect-Funktion), der ausgelöst wird, wenn das beobachtete element übergibt die angegebenen Schwellenwert und das Optionen-Objekt führt, dass unsere Beobachter-Optionen.

Apropos das options-Objekt, verwendet es eine Wurzel, unser Referenz-Objekt, das wir verwenden, um die Sichtbarkeit unserer beobachtete element. Es könnte sein Vorfahr des Objekts oder unseren browser-viewport, wenn wir übergeben Sie null. Das Objekt gibt auch ein Schwellenwert, kann variieren von 0 bis 1 und sagt uns, auf wie viel Prozent das Ziel, die Sichtbarkeit der observer callback ausgeführt werden soll, mit 0 Sinn sobald auch nur ein pixel sichtbar ist, und 1, was bedeutet, das gesamte element muss sichtbar sein.

Und dann, nach der Erstellung der Kreuzung Beobachter, wir bringen es zu unserem element mit der Methode beobachten.

Funktion createObserver() {
const options = {
root: null,
Schwelle: “0”
};
const observer = new IntersectionObserver(handleIntersect, Optionen);
Beobachter.beobachten(el);
}

Schritt 5: Registrieren der Richtlinie

Nutzen Sie unsere neu erstellte Richtlinie, die wir zunächst brauchen, um es zu registrieren. Es gibt zwei Möglichkeiten, es zu tun: weltweit (überall verfügbar, in der app) oder lokal (auf einer bestimmten Komponente Ebene).

Global registration

Für die Globale Registrierung, importieren wir unsere Richtlinie und verwenden Sie den Vue.Richtlinie-Methode übergeben Sie den Namen wollen wir nennen unsere Richtlinie und die Richtlinie selbst. Das ermöglicht es uns, fügen Sie eine v-lazyload-Attribut für jedes element im code.

// main.js
import Vue von “vue”;
import App from “./App”;
import LazyLoadDirective von “./Richtlinien/LazyLoadDirective”;

Vue.config.productionTip = false;

Vue.Richtlinie(“lazyload”, LazyLoadDirective);

neue Vue({
el: “#app”,
components: { App },
Vorlage: “<App/>”
});
Die lokale Registrierung

Wenn wir wollen, nutzen Sie unsere Richtlinie, die nur in einer bestimmten Komponente, und beschränken Sie den Zugang zu ihm, können wir registrieren die Richtlinie lokal. Um das zu tun, müssen wir importieren Sie die Richtlinie in der Komponente, die Sie benutzen, und registrieren Sie es in den Richtlinien-Objekt. Das gibt uns die Möglichkeit, weitere v-lazyload-Attribut auf jedes element in dieser Komponente.

import LazyLoadDirective von “./Richtlinien/LazyLoadDirective”;

export default {
Richtlinien: {
lazyload: LazyLoadDirective
}
}

Schritt 6: Verwenden Sie eine Richtlinie, die die ImageItem Komponente

Nun, dass unsere Richtlinie registriert worden ist, können wir es verwenden, durch hinzufügen von v-lazyload auf das übergeordnete element, das trägt unser Bild (die Abbildung-tag in unserem Fall).

<Vorlage>
<Abbildung v-lazyload class=”Bild – __ – wrapper”>
<ImageSpinner
class=”image__spinner”
/>
<img
class=”image__item”
:data-url=”Quelle”
alt=”random image”
>
</figure>
</template>

Browser-Unterstützung

Wir wären nachlässig, wenn wir nicht einen Hinweis über die browser-Unterstützung. Obwohl die Kreuzung Beobachten-API ist es nicht von allen Browsern unterstützt, es deckt 73% der Nutzer (als dies geschrieben wurde).

Dieser browser support-Daten von Caniuse, welche hat mehr Details. Eine Zahl zeigt an, dass browser die Funktion unterstützt in dieser version.

Desktop

ChromeOperaFirefoxIEEdgeSafari
58 45 55 Keine 16 Keine

Mobile / Tablet

iOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox
Keine 46 Keine 67 69 62

Nicht schlecht. Gar nicht so schlecht.

Aber! In dem Bewusstsein, dass wir zeigen wollen Bilder für alle Benutzer (denken Sie daran, dass die Verwendung von Daten-url, die verhindert, dass das Bild geladen wird), müssen wir hinzufügen, ein Stück mehr zu unserer Richtlinie. Speziell, wir müssen überprüfen, ob der browser unterstützt die Kreuzung Beobachter, und es tut es nicht, Feuer loadImage statt. Das wird unsere fallback.

if (window[“IntersectionObserver”]) {
createObserver();
} else {
loadImage();
}

Zusammenfassung

Faul laden von Bildern, die erheblich verbessern kann die Seiten-performance, da es dauert, die Seite, Gewicht hogged durch Bilder und lädt diese nur wenn der Benutzer auch tatsächlich braucht.

Für diejenigen, die noch nicht davon überzeugt, ob es sich lohnt das Spiel mit lazy loading, hier einige raw-Nummern aus dem einfachen Beispiel, das wir verwendet haben. Die Liste enthält 11 Artikel mit einem Bild pro Artikel. Das ist insgesamt 11 Bilder (Mathe!). Es ist nicht so, dass die eine Tonne von Bildern aber können wir noch mit ihm zu arbeiten.

Hier ist, was wir bekommen zerreißen alle 11 Bilder ohne lazy loading auf eine 3G-Verbindung:

11 Bild-Anforderungen tragen zu einer insgesamt Seite Größe von 3,2 MB. Oomph.

Hier die gleiche Seite setzen lazy loading task:

Sagen Sie, was? Nur eine Anfrage für ein Bild. Unsere Seite ist jetzt 1.4 MB. Gespart haben wir 10 Anfragen und verringert die Größe der Seite von 56%.

Ist es ein einfaches und Isoliertes Beispiel? Ja, aber die zahlen sprechen noch für sich selbst. Hoffentlich findest du lazy loading ein effektiver Weg, um den Kampf gegen die Seite aufblähen, und dass dieser spezifische Ansatz mit Vue mit Kreuzung Beobachter kommt in handliches.