Skip to content

Vue中Lazyload的一种实现 #175

Open
@louzhedong

Description

本文实现一个基于Vue directive的Lazyload

实现

// throttle.js
const throttle = function (fn, delay = 200) {
  let lastDate = 0; // 上次执行事件

  return function () {
    const context = this, argument = arguments;
    const now = +new Date();
    if (now - lastDate > delay) {
      lastDate = now;
      fn.apply(context, argument);
    }
  }
}

export default throttle;

// Lazyload.js
import throttle from '@/common/utils/throttle.js';

function replaceImgSrc(el, binding, vnode) {

  const rect = el.getBoundingClientRect();
  if (rect.top < document.documentElement.clientHeight) {
    if (!el.src) {
      el.src = binding.value;
      // 图片加载完成后,将图片的高度变成原本的高度
      let image = new Image();
      image.onload = function () {
        if (vnode.data.attrs && vnode.data.attrs.height) {
          el.height = vnode.data.attrs.height;
        } else {
          el.height = image.height;
        }
        if (vnode.data.attrs && vnode.data.attrs.width) {
          el.width = vnode.data.attrs.width;
        }
      }
      image.src = binding.value;
    }
  }
}

function bindEvent(el, binding, vnode) {
  replaceImgSrc(el, binding, vnode);
  const throttleCb = throttle(replaceImgSrc, 200);

  el.bindScrollListener = throttleCb.bind(this, el, binding, vnode);
  document.addEventListener('scroll', el.bindScrollListener);
}

function _init(el, binding, vnode) {
  el.height = (vnode.data.attrs && vnode.data.attrs.height) || 300; // 给图片定一个默认高度
  el.width = (vnode.data.attrs && vnode.data.attrs.width) || document.documentElement.clientWidth;
}

export default {
  bind(el, binding, vnode) {
    _init(el, binding, vnode);
    const vm = vnode.context;
    if (vm._isMounted) {
      bindEvent(el, binding, vnode);
    }
    vm.$on('hook:mounted', bindEvent.bind(this, el, binding, vnode));
  },

  unbind(el) {
    document.removeEventListener('scroll', el.bindScrollListener);
  }
}


// 在main.js中定义指令
import LazyLoad from './Lazyload/src/Lazyload';
Vue.directive('LazyLoad', LazyLoad);

// 使用
<template>
  <ul class="lazy-load-example">
    <li v-for="(item, index) in imgList" :key="index">
      <img v-lazy-load="item" />
    </li>
  </ul>
</template>

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions