Lui Laden van Afbeeldingen met Vue.js Richtlijnen en Kruising Waarnemer

0
23

Als ik denk over web performance, het eerste wat in me opkomt is hoe beelden zijn over het algemeen de laatste elementen die op de pagina worden weergegeven. Vandaag foto ‘ s kunnen een groot probleem zijn als het gaat om prestaties, dat is jammer omdat de snelheid waarmee een website laadt, heeft een directe impact op de gebruikers die met succes doen wat ze kwam naar de pagina om te doen (denk gesprek tarieven).

Zeer onlangs, Rahul Nanwani schreef een uitgebreide gids over luie het laden van afbeeldingen. Ik zou graag betrekking hebben op hetzelfde onderwerp, maar vanuit een andere benadering: het gebruik van gegevensverbindingen kenmerken, Kruispunt Waarnemer en aangepaste richtlijnen in Vue.js.

Wat dit zal doen in principe is ons toelaten om het oplossen van twee dingen:

  1. Het opslaan van de src van het beeld dat we willen laden zonder deze te laden in de eerste plaats.
  2. Detecteren wanneer de afbeelding wordt zichtbaar voor de gebruiker en het activeren van de aanvraag voor het laden van de afbeelding.

Dezelfde fundamentele lazy loading concept, maar een andere manier om te gaan over.

Ik heb een voorbeeld op basis van een voorbeeld beschreven door Benjamin Taylor in zijn blog post. Het bevat een lijst van willekeurige artikelen elk met een korte beschrijving, afbeelding en een link naar de bron van het artikel. We zullen gaan door het proces van het maken van een component die is belast met het weergeven van de lijst, waardoor een artikel, lui en het laden van de afbeelding voor een specifiek artikel.

Let ‘ s get lui! Of op zijn minst break-dit onderdeel omlaag stuk-voor-stuk.

Stap 1: Maak de ImageItem component in Vue

Laten we beginnen met het maken van een component die een afbeelding tonen (maar met geen lui laden betrokken zijn gewoon nog niet). We noemen dit bestand ImageItem.vue. In het onderdeel sjabloon gebruiken we een figuur-tag met ons imago — het beeld tag zelf ontvangt het src-attribuut dat verwijst naar de bron-URL voor de afbeelding.

<sjabloon>
<figure class=”image – __ – wrapper”>
<img
class=”image – __ – item”
:src=”bron”
alt=”willekeurige afbeelding”
>
</figure>
</template>

In het script sectie van de component, ontvangen we de prop bron die we gebruiken om de src url van de afbeelding die we weergeven.

export standaard {
naam: “ImageItem”,
rekwisieten: {
bron: {
type: String,
nodig: true
}
}
};

Dit alles is perfect in orde en maken het beeld normaal is. Maar, als we vertrekken is het hier, de afbeelding wordt geladen rechte weg zonder te wachten voor de gehele component te renderen. Dat is niet wat we willen, dus ga naar de volgende stap.

Stap 2: Voorkomen dat de afbeelding wordt geladen wanneer het onderdeel is gemaakt

Het klinkt misschien een beetje grappig is dat we willen voorkomen dat iets uit te laden wanneer we willen laten zien, maar dit is over het laden van het op de juiste tijd in plaats van te blokkeren voor onbepaalde tijd. Om te voorkomen dat de afbeelding wordt geladen, we moeten om zich te ontdoen van het src-attribuut van de img-tag. Maar, we moeten nog steeds op te slaan ergens dus we kunnen er gebruik van maken als we willen. Een goede plek om te houden dat de informatie in een data – attribuut. Deze laten ons toe om informatie op te slaan op een standaard, semantische HTML-elementen. In feite, kan je al gewend zijn om ze te gebruiken als JavaScript kiezers.

In dit geval, ze zijn perfect voor onze behoeften!

<!–ImageItem.vue–>
<sjabloon>
<figure class=”image – __ – wrapper”>
<img
class=”image – __ – item”
:data-url=”bron” // yay voor data-attributen!
alt=”willekeurige afbeelding”
>
</figure>
</template>

Met dat onze afbeelding niet laden omdat er geen bron-URL te trekken uit.

Dat is een goed begin, maar nog niet helemaal wat we willen. Willen We laden onze afbeelding onder specifieke voorwaarden. We kunnen op verzoek van de afbeelding te laden door het vervangen van het src attribuut met de afbeelding bron-URL gehouden in onze data-url-kenmerk. Dat is het eenvoudige deel. De echte uitdaging is het uitzoeken wanneer het te vervangen met de werkelijke bron.

Ons doel is om de pin-code van de lading naar het scherm van de gebruiker plaats. Dus, als de gebruiker scrollt naar een punt waar de afbeelding in beeld komt, dat is waar het wordt geladen.

Hoe kunnen we vaststellen of de afbeelding in de weergave of niet? Dat is onze volgende stap.

Stap 3: Detecteren wanneer de afbeelding is zichtbaar voor de gebruiker

U hebt ervaring met JavaScript om te bepalen wanneer een element is in zicht. Mogelijk hebt u ook ervaring liquidatie met enkele knoestige script.

Bijvoorbeeld, kunnen we gebruik maken van gebeurtenissen en de gebeurtenis-handlers voor het detecteren van de scroll-positie, offset waarde-element hoogte, en viewport hoogte, bereken dan of een afbeelding in de viewport of niet. Maar dat klinkt al knoestige, niet?

Maar het kan erger. Dit heeft directe gevolgen voor de prestaties. Die berekeningen zou worden ontslagen op elke scroll event. Erger nog, stel je voor een paar tiental foto ‘ s, die elk om te berekenen of het nu zichtbaar is of niet op elke scroll event. Waanzin!

Kruising Waarnemer aan de redding! Dit zorgt voor een zeer efficiënte manier van opsporen als er een element is zichtbaar in de viewport. Specifiek, kunt u een terugbel die wordt geactiveerd wanneer een element — de doel — snijdt met het apparaat viewport of een bepaald element.

Dus, wat we moeten doen om het te gebruiken? Een paar dingen:

  • het maken van een nieuwe kruising waarnemer
  • bekijk het element dat we willen lui belasting voor de zichtbaarheid verandert
  • plaats het element als het element is in de viewport (door het vervangen van src is met onze gegevens-url)
  • stoppen met het kijken voor de zichtbaarheid verandert (unobserve) na het laden is voltooid

Vue.js aangepaste richtlijnen wikkel deze functionaliteit samen en gebruiken het als we moeten, zo vaak als we het nodig hebben. Om die te gebruiken is onze volgende stap.

Stap 4: Maak een Vue aangepaste richtlijn

Wat is een aangepaste richtlijn? Vue de documentatie beschrijft het als een manier om low-level DOM toegang op basis van elementen. Bijvoorbeeld het wijzigen van een attribuut van een specifiek DOM-element dat, in ons geval, kan het veranderen van het src-attribuut van een img-element. Perfect!

We breken in een moment, maar hier is waar we hier naar kijken, zo ver als de code:

export standaard {
geplaatst: el => {
functie loadImage() {
const imageElement = Array.van(el.kinderen).zoeken(
el => el.knooppuntnaam === “IMG”
);
als (imageElement) {
imageElement.addEventListener(“load”, () => {
setTimeout(() => el.classList.toevoegen(“geladen”), 100);
});
imageElement.addEventListener(“error”, () => console.log(“fout”));
imageElement.src = imageElement.dataset.de url;
}
}

functie handleIntersect(items, waarnemer) {
vermeldingen.forEach(entry => {
if (ingang.isIntersecting) {
loadImage();
waarnemer.unobserve(el);
}
});
}

functie createObserver() {
const options = {
root: null,
drempel: “0”
};
const waarnemer = nieuwe IntersectionObserver(handleIntersect, opties);
waarnemer.observeren(el);
}
if (window[“IntersectionObserver”]) {
createObserver();
} else {
loadImage();
}
}
};

OK, we pakken het stap-voor-stap.

De haak-functie stelt ons in staat om het vuur een aangepaste logica op een bepaald moment van een afhankelijk element levenscyclus. We maken gebruik van de geplaatste haak want het is heet wanneer de afhankelijke element is geplaatst in het bovenliggende knooppunt (dit staat garant voor het bovenliggende knooppunt aanwezig is). Daar willen we observeren de zichtbaarheid van een element in de relatie tot zijn ouders (of een voorouder), moeten we gebruik maken van de haak.

export standaard {
geplaatst: el => {

}
}

De loadImage functie is verantwoordelijk voor het vervangen van de src-waarde met de data-url. In hem hebben wij de toegang tot onze element (el), waarin we de toepassing van de richtlijn. Kunnen We halen de img van dat element.

Vervolgens controleren we of de afbeelding bestaat en als het bestaat, voegen we een luisteraar die het vuur van een callback-functie wanneer het laden is voltooid. Die aanroep zal verantwoordelijk zijn voor het verbergen van de spinner en het toevoegen van de animatie (fade-in effect) om de afbeelding met behulp van een CSS-klasse. We voegen ook een tweede luisteraar die genoemd worden in het geval dat de URL niet kan worden geladen.

Tenslotte vervangen we de src van onze img-element met de URL van de bron van de afbeelding en laat het zien!

functie loadImage() {
const imageElement = Array.van(el.kinderen).zoeken(
el => el.knooppuntnaam === “IMG”
);
als (imageElement) {
imageElement.addEventListener(“load”, () => {
setTimeout(() => el.classList.toevoegen(“geladen”), 100);
});
imageElement.addEventListener(“error”, () => console.log(“fout”));
imageElement.src = imageElement.dataset.de url;
}
}

We gebruiken Kruising Waarnemer handleIntersect functie, die verantwoordelijk is voor het afvuren van loadImage wanneer aan bepaalde voorwaarden wordt voldaan. Specifiek, het is ontslagen bij het Kruispunt Waarnemer ontdekt dat het element komt in de viewport of een ouder component-element.

De functie heeft toegang tot items, die bestaat uit een array van alle elementen, die worden bekeken door de waarnemer en de waarnemer zelf. We doorlopen items en controleren of een enkel item zichtbaar wordt op onze gebruiker met isIntersecting — en vuur de loadImage functie als het is. Zodra de afbeelding is aangevraagd, we unobserve het element (verwijderen van de waarnemer watch-lijst), die voorkomt dat de afbeelding wordt geladen. En opnieuw. En opnieuw. En…

functie handleIntersect(items, waarnemer) {
vermeldingen.forEach(entry => {
if (ingang.isIntersecting) {
loadImage();
waarnemer.unobserve(el);
}
});
}

Het laatste stuk is de createObserver functie. Deze man is verantwoordelijk voor het creëren van onze Kruising Waarnemer en de bevestiging aan ons element. De IntersectionObserver constructor accepteert een callback (onze handleIntersect functie) die wordt geactiveerd wanneer de waargenomen element voor het doorgeven van de opgegeven drempel en de opties object dat draagt onze waarnemer opties.

Het spreken van de opties object, het maakt gebruik van root onze referentie-object, die we gebruiken om de zichtbaarheid van onze bekeken element. Het is misschien een voorvader van het object of onze browser viewport als we null doorgeven. Het object geeft ook een drempel waarde die kan variëren van 0 tot 1 en vertelt ons op welke procent van de doelgroep de zichtbaarheid van de waarnemer callback moet worden uitgevoerd, waarbij 0 betekent zo snel als zelfs een pixel zichtbaar is en 1 betekent dat de hele element moet zichtbaar zijn.

En dan, na het maken van de Kruising Waarnemer, wij hechten aan ons element met behulp van de methode observeren.

functie createObserver() {
const options = {
root: null,
drempel: “0”
};
const waarnemer = nieuwe IntersectionObserver(handleIntersect, opties);
waarnemer.observeren(el);
}

Stap 5: het Registreren van richtlijn

Voor het gebruik van onze nieuw gemaakte richtlijn, moeten we eerst te registreren. Er zijn twee manieren om het te doen: wereldwijd (overal beschikbaar in de app) of lokaal (op een bepaalde component niveau).

Wereldwijde registratie

Voor de wereldwijde registratie, importeren wij onze richtlijn en het gebruik van de Vue.richtlijn methode voor het doorgeven van de naam we willen onze richtlijn en de richtlijn zelf. Dat stelt ons in staat om toe te voegen een v-lazyload attribuut van een element in onze code.

// main.js
importeren Vue van “vue”;
importeren-App uit “./App”;
importeren LazyLoadDirective uit “./richtlijnen/LazyLoadDirective”;

Vue.config.productionTip = false;

Vue.richtlijn(“lazyload”, LazyLoadDirective);

nieuwe Vue({
el: “#app”,
onderdelen: { App },
sjabloon: “<App/>”
});
Lokale registratie

Als we willen ons richtlijn alleen in een specifieke component en het beperken van de toegang tot het, we kunnen registreren van de richtlijn lokaal. Om dat te doen, moeten we importeren de richtlijn binnen de component die zal gebruiken en te registreren in de richtlijnen object. Dat geeft ons de mogelijkheid om een v-lazyload attribuut van een element in dat onderdeel.

importeren LazyLoadDirective uit “./richtlijnen/LazyLoadDirective”;

export standaard {
richtlijnen: {
lazyload: LazyLoadDirective
}
}

Stap 6: Gebruik een richtlijn op de ImageItem component

Nu dat onze richtlijn is geregistreerd, kunnen we gebruik maken van het door het toevoegen van v-lazyload op de bovenliggende element dat de drager van de afbeelding (de afbeelding tag in ons geval).

<sjabloon>
<figuur v-lazyload class=”image – __ – wrapper”>
<ImageSpinner
class=”image__spinner”
/>
<img
class=”image – __ – item”
:data-url=”bron”
alt=”willekeurige afbeelding”
>
</figure>
</template>

Browser Ondersteuning

We zouden nalatig zijn als we niet een opmerking over steun van de browser. Hoewel de Kruising Observeren API wordt niet door alle browsers ondersteund, het behandelt 73% van de gebruikers (van dit schrijven).

Deze browser ondersteunt data is van Caniuse, die heeft meer detail. Een aantal geeft aan dat browser ondersteunt de functie aan die versie.

Desktop

ChromeOperaFirefoxIEEdgeSafari
58 45 55 Geen 16 Geen

Mobiele / Tablet

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

Niet slecht. Helemaal niet slecht.

Maar! Met in het achterhoofd dat we willen afbeeldingen tonen aan alle gebruikers (vergeet niet dat het gebruik van data-url voorkomt dat de afbeelding wordt geladen), moeten we nog een stuk naar onze richtlijn. Specifiek, moeten we om te controleren of de browser ondersteunt Kruising Waarnemer, en het niet, brand loadImage plaats. Dit zal onze fallback.

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

Samenvatting

Lui laden van afbeeldingen aanzienlijk kan verbeteren pagina van de prestaties, want het duurt voordat de pagina gewicht stokt door beelden en laadt ze in alleen wanneer de gebruiker daadwerkelijk nodig heeft.

Voor degenen die nog niet overtuigd als het is de moeite waard te spelen met lazy loading, hier zijn een paar cijfers van het eenvoudige voorbeeld dat we gebruiken. De lijst bevat 11 artikelen met één afbeelding per artikel. Dat is een totaal van 11 afbeeldingen (wiskunde!). Het is niet zo dat is een ton van de beelden, maar we kunnen nog steeds werken.

Hier is wat we krijgen scheuren alle 11 foto ‘ s zonder lui laden op een 3G-verbinding:

De 11 afbeelding verzoeken bijdragen tot een algemene pagina grootte van 3.2 MB. Oomph.

Hier is het dezelfde pagina zetten lazy loading tot taak:

Wat zegt u? Slechts één aanvraag voor één beeld. Onze pagina is nu 1.4 MB. We gered 10 aanvragen en verminderd de pagina met 56%.

Is het een eenvoudige en geïsoleerd voorbeeld? Ja, maar de nummers nog steeds spreken voor zich. Hopelijk vind je luie het laden van een effectieve manier om de strijd tegen pagina zwellen en dat deze specifieke aanpak met behulp van Vue met Snijpunt Waarnemer van pas komt.