1. Introduction to project implementation

Vue Project Construction Refer to Webpack4 VUE Project Construction

Vuepress is the official document of vuepress.vuejs.org

Github Pages + gh-page

The project addressGithub.com/zxpsuper/vu…

File address zxpsuper.github. IO /vui-vue

In the stage of self exploration, looking forward to leaving your valuable advice!

2. Basic implementation of V-lazy

The basic principle of lazy image loading:

  1. Replace the target image with a placeholder firstsrcAttribute values
  2. As the picture of theoffsetTop < innerHeight + scrollTop, that is, the picture appears inside the window, then modifysrcA value ofdata-srcThe value of the
  3. Of course, all this requires constant listening for rolling events

Start by implementing a lazy loading function

var img = document.getElementsByTagName('img');
function lazyload() {
        // Listen for page scroll events
        var seeHeight = window.innerHeight; // Height of visible area
        var scrollTop =
            document.documentElement.scrollTop || document.body.scrollTop; // Height of scroll bar from top
        for (var i = 0; i < img.length; i++) {
            if (img[i].getAttribute('data-image-show')) continue; // If the load is complete, there is no need to go through the following process
            if (img[i].offsetTop < seeHeight + scrollTop) {
                console.log(img[i].offsetTop, seeHeight, scrollTop);
                if (img[i].getAttribute('src') == Vue.$vuiLazyLoad.img) {
                    img[i].src = img[i].getAttribute('data-src');
                    img[i].setAttribute('data-image-show'.'true'); // Indicate that the load is complete}}}}Copy the code

Scroll to monitor

Scroll monitoring, continuous scrolling will continue to trigger the function of scroll monitoring, affecting performance, so it is necessary to add an anti-shake function

// The buffeting function
function debounce(event, time) {
    let timer = null;
    return function(. args) {
        if (timer) clearTimeout(timer)
        timer = setTimeout((a)= > {
                timer = null;
                event.apply(this, args);
            }, time);
    };
}
Copy the code

Add and remove listeners

window.removeEventListener('scroll', debounce(lazyload, 800));
window.addEventListener('scroll', debounce(lazyload, 800));
Copy the code

Add the instruction

We use the three hook functions in the custom directive bind, INSERTED, and unbind, and we want to make the placeholder in the directive modifiable, so we write it as a function

const lazyload = function(Vue) {
    var img = document.getElementsByTagName('img'), evenFunction;
    function lazyload() {
        // Listen for page scroll events
        var seeHeight = window.innerHeight; // Height of visible area
        var scrollTop =
            document.documentElement.scrollTop || document.body.scrollTop; // Height of scroll bar from top
        for (var i = 0; i < img.length; i++) {
            if (img[i].getAttribute('data-image-show')) continue; // If the load is complete, there is no need to go through the following process
            if (img[i].offsetTop < seeHeight + scrollTop) {
                console.log(img[i].offsetTop, seeHeight, scrollTop);
                if (img[i].getAttribute('src') == Vue.$vuiLazyLoad.img) {
                    img[i].src = img[i].getAttribute('data-src');
                    img[i].setAttribute('data-image-show'.'true'); // Indicate that the load is complete}}}}// The default configuration in vUI. You can modify the placeholder map by modifying Vue.$vuiLazyLoad
    Vue.$vuiLazyLoad = {
        img:
            'https://github.com/zxpsuper/Demo/blob/master/images/avatar.jpg?raw=true'.imgLength: 0.// The number of lazy images to load, when the number is 0 remove the scroll listener
    };
    
    lazyload(); // when the page is loaded, the image in the area is loaded
    evenFunction = debounce(lazyload, 800);
    window.removeEventListener('scroll', evenFunction);
    window.addEventListener('scroll', evenFunction);
    return {
        name: 'lazy'./ / binding
        bind(el, binding) {
            el.setAttribute('src', Vue.$vuiLazyLoad.img);
            el.setAttribute('data-src', binding.value);
            Vue.$vuiLazyLoad.imgLength++;
        },
        / / insert
        inserted(el) {
            / / empty for the time being
        },
        / / unbundling
        unbind() {
            Vue.$vuiLazyLoad.imgLength--; // Each time you unbind, subtract
            if(! Vue.$vuiLazyLoad.imgLength && evenFunction)window.removeEventListener('scroll', evenFunction); }}; }Copy the code

Using new featuresIntersectionObserver

The IntersectionObserver interface (which is part of the IntersectionObserver API) provides developers with a way to asynchronously monitor the intersectionstate of a target element with its ancestors or viewports.

Check to see if the element crosses the window, if so, change the SCR to data-src, and remove the observation state. Of course, all this is provided that you observe the image itself at the time of image creation, and therefore in the hook function at image insertion

inserted(el) {
    if (IntersectionObserver) lazyImageObserver.observe(el);
},
Copy the code

Specific use method:

let lazyImageObserver
if (IntersectionObserver) {
    lazyImageObserver = new IntersectionObserver((entries, observer) = > {
        entries.forEach((entry, index) = > {
            let lazyImage = entry.target;
            // If the element is visible
            if (entry.intersectionRatio > 0) {
                if (lazyImage.getAttribute('src') == Vue.$vuiLazyLoad.img) {
                    lazyImage.src = lazyImage.getAtstribute('data-src');
                }
                lazyImageObserver.unobserve(lazyImage); // Remove the observation}}); }); }Copy the code

Of course, IntersectionObserver is preferred. Otherwise, traditional methods will be used

Registration instructions

import Vue from 'vue'
Vue.directive('lazy', lazyLoad(Vue));
Copy the code

3. Complete code

const lazyLoad = function(Vue) {
    var img = document.getElementsByTagName('img');
    function lazyload() {
        console.log('rolling lazy');
        // Listen for page scroll events
        var seeHeight = window.innerHeight; // Height of visible area
        var scrollTop =
            document.documentElement.scrollTop || document.body.scrollTop; // Height of scroll bar from top
        for (var i = 0; i < img.length; i++) {
            if (img[i].getAttribute('data-image-show')) continue;
            if (img[i].offsetTop < seeHeight + scrollTop) {
                console.log(img[i].offsetTop, seeHeight, scrollTop);
                if (img[i].getAttribute('src') == Vue.$vuiLazyLoad.img) {
                    img[i].src = img[i].getAttribute('data-src');
                    img[i].setAttribute('data-image-show'.'true');
                }
            }
        }
    }
    Vue.$vuiLazyLoad = {
        img:
            'https://github.com/zxpsuper/Demo/blob/master/images/avatar.jpg?raw=true'.imgLength: 0};var lazyImageObserver, evenFunction;

    if (IntersectionObserver) {
        lazyImageObserver = new IntersectionObserver((entries, observer) = > {
            entries.forEach((entry, index) = > {
                let lazyImage = entry.target;
                // If the element is visible
                if (entry.intersectionRatio > 0) {
                    if (lazyImage.getAttribute('src') == Vue.$vuiLazyLoad.img) {
                        lazyImage.src = lazyImage.getAttribute('data-src'); } lazyImageObserver.unobserve(lazyImage); }}); }); }else {
        lazyload(); // when the page is loaded, the image in the area is loaded
        evenFunction = debounce(lazyload, 800);
        window.removeEventListener('scroll', evenFunction);
        window.addEventListener('scroll', evenFunction);
    }
    return {
        name: 'lazy',
        bind(el, binding) {
            el.setAttribute('src', Vue.$vuiLazyLoad.img);
            el.setAttribute('data-src', binding.value);
            Vue.$vuiLazyLoad.imgLength++;
        },
        inserted(el) {
            if (IntersectionObserver) lazyImageObserver.observe(el);
        },
        unbind() {
            Vue.$vuiLazyLoad.imgLength--;
            if(! Vue.$vuiLazyLoad.imgLength && evenFunction)window.removeEventListener('scroll', evenFunction); }}; };export default lazyLoad;

function debounce(event, time) {
    let timer = null;
    return function(. args) {
        if (timer) clearTimeout(timer);
        timer = setTimeout((a)= > {
            timer = null;
            event.apply(this, args);
        }, time);
    };
}

Copy the code

conclusion

This article is the comprehensive realization of vUE custom instruction and lazy loading principle, if there are mistakes, hope to point out common progress.

More recommended

Advanced_front_end

Daily question

Webpack4 Build Vue application (createVue)

Canvas Advanced (1) Generation of two-dimensional code and scan code recognition

Canvas advanced (2) Write a NPM plug-in to generate a TWO-DIMENSIONAL code with logo

Canvas advanced (3) TS + Canvas rewrite “color discrimination” small game

Canvas advanced (four) to achieve a “scratch-off” game