手写vue2的Lazyload

调用方式,express写个后台服务调图片,具体使用不贴了

import VueLazyload from "./modules/vue-lazyload";

Vue.use(VueLazyload,{
  loading: 'http://localhost:3000/images/loading.gif',
  error: 'http://localhost:3000/images/error.jpg',
  preload: 1 // 倍数
});

使用指令

<img v-lazy="item.src" :alt="item.title">

vueLazyload/index.js

import Lazyload from './Lazyload';
const VueLazyload = {
  install(Vue, options) {
    const LazyClass = Lazyload(Vue)
    const lazyload = new LazyClass(options);
    Vue.directive('lazy', {
      bind: lazyload.bindLazy.bind(lazyload)
    })
  }
}
export default VueLazyload;

vueLazyload/Lazyload.js

import Lazyimg from "./Lazyimg";
import {
  getScrollParent
} from "./utils";

// 柯里化
export default function Lazyload(Vue) {
  return class Lazy {
    constructor(options) {
      this.options = options;
      this.isAddScrollListener = false;
      this.lazyImgPool = [];
    }
    bindLazy(el, bindings, vnode) {
      // console.log(this.options);
      // 还未渲染
      Vue.nextTick(() => {
        const scrollParent = getScrollParent(el);
        // console.log('scrollParent', scrollParent);
        if (scrollParent && !this.isAddScrollListener) {
          scrollParent.addEventListener('scroll', this.handleScroll.bind(this), false)
          //true 表示在捕获阶段调用事件处理程序,false(默认值)表示在冒泡阶段调用事件处理程序

        }
        const lazyImg = new Lazyimg({
          el,
          src: bindings.value,
          options: this.options,
          imgRender: this.imgRender.bind(this)
        })
        // 图片池
        this.lazyImgPool.push(lazyImg);
        this.handleScroll(); // 初始化时显示一部分可视区域内的图片
      })
    }
    handleScroll() {
      let isVisible = false;
      this.lazyImgPool.forEach(lazyImg => {
        if (!lazyImg.loaded) { // 未加载
          isVisible = lazyImg.checkIsVisible() //检测是否出现在区域内
          isVisible && lazyImg.loadImg() // 出现了加载图片

        }
      })
    }
    imgRender(lazyImg, state) {
      const {
        el,
        options
      } = lazyImg;
      const {
        loading,
        error
      } = options;
      let src = '';
      switch (state) {
        case 'loading':
          src = loading || '';
          break;
        case 'error':
          src = error || '';
          break;
        default:
          src = lazyImg.src;
          break;
      }
      el.setAttribute('src', src);
    }
  }
}

vueLazyload/Lazyimg.js

/* 处理每张图片的类 */
import {
  imgLoad
} from "./utils";
export default class Lazyimg {
  constructor({
    el,
    src,
    options,
    imgRender
  }) {
    this.el = el
    this.src = src
    this.options = options

    this.imgRender = imgRender //渲染事件
    this.loaded = false //加载完没
    this.state = { // 状态
      loading: false,
      error: false
    }
  }
  checkIsVisible() {
    // 当前图片距离最顶端距离是多少来判断
    const {
      top
    } = this.el.getBoundingClientRect();
    return top < window.innerHeight * (this.options.preload || 1.3); // 小于倍数
  }
  loadImg() {
    this.imgRender(this.el, 'loading');

    imgLoad(this.src).then(() => {
      this.state.loading = true;
      this.imgRender(this, 'ok');
      this.loaded = true;
    }, () => {
      this.state.error = true;
      this.imgRender(this, 'error');
      this.loaded = true;
    })
  }
}

vueLazyload/utils.js

export function getScrollParent(el) {
  let _parent = el.parentNode;

  while (_parent) {
    // 查找父节点是否有style overflow:auto
    const styleOverflow = window.getComputedStyle(_parent)['overflow'];

    if (/(scroll)|(auto)/.test(styleOverflow)) {
      return _parent;
    }
    _parent = _parent.parentNode;
  }
}
export function imgLoad(src) {
  return new Promise((resolve, reject) => {
    const oImg = new Image();
    oImg.src = src;
    oImg.onload = resolve;
    oImg.onerror = reject;
  })
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yusirxiaer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值