vue自定义指令实现图片懒加载

前言

图片懒加载原理

1.初始化src属性设置为默认图片(占位图片)
2 .img标签自定义一个属性存储图片真实url
3.监听页面滚动,当图片出现在可视区域把真实url赋值给src

前2步都很容易实现,第三步怎么判断图片是否出现在可视区域?

通过element.getBoundingClientRect()可获知图片顶部和底部分别距离可视区域顶部距离,假设
分别为elTop(图片顶部距离可视区域顶部距离),elBottom(图片底部距离可视区域顶部距离),windowHeight(可视区域高度),当满足elTop-windowHeight<0&&elBottom>0时图片刚好出现在可视区域内

当然也可以通过新兴的API IntersectionObserver判断是否出现在可视区域,兼容性不好这里就不采用了

代码实现

lazyLoadImage.js(自定义指令文件)

const lazyLoadImage = defaultImage => {
    let windowHeight = document.documentElement.clientHeight || document.body.clientHeight//可视区域高

    function throttle(fn, delay) {//节流
        let timeout = null
        return (...args) => {
            if (timeout) return
            timeout = setTimeout(() => {
                fn.apply(this, args)
                timeout = null
            }, delay);
        }

    }
    function loadImage(el) {//加载图片
        return () => {
            let top = el.getBoundingClientRect().top
            let bottom = el.getBoundingClientRect().bottom
            if (top - windowHeight < 0 && bottom > 0&&el.hasAttribute('data-src')) {//图片出现在可视区域内开始加载图片
                el.src = el.getAttribute('data-src')
                el.removeAttribute('data-src')

            }
        }
    }

    return {
        bind(el, binding) {
            el.src = defaultImage
            el.setAttribute('data-src', binding.value) 
        },
        inserted(el) {
            loadImage(el)()//显示初始(首屏)图片
            window.addEventListener('scroll', throttle(loadImage(el), 500))//每滚动500毫秒加载一次图片
        }

    }
}


const install = {
    install(vue, defaultImage) {
        //v-lazy
        vue.directive('lazy', lazyLoadImage(defaultImage))
    }
}

export default install

main.js

import lazyLoadImage from './directive/lazyLoadImage'
const defaultImage=require('@/assets/loading.gif')//默认占位图片
Vue.use(lazyLoadImage,defaultImage)

页面引用(v-lazy="真实url)"

<template>
  <div class="page">
    <img class="image" v-for="item in imageList" :key="item" v-lazy="item" />
  div>
template>
export default {
  data() {
    return {
      imageList: [
        "https://xxxxxxxx1",
        "https://xxxxxxxx2",
        "https://xxxxxxxx3",
        "https://xxxxxxxx4",
        "https://xxxxxxxx5",
        "https://xxxxxxxx6",
        "https://xxxxxxxx7",
        "https://xxxxxxxx8",
        "https://xxxxxxxx9",
        "https://xxxxxxxx10",
      ],
    };
  },

效果

你可能感兴趣的:(vue.js,前端,javascript)