Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intersection Observer + Vue指令 优雅实现图片懒加载 #73

Open
amandakelake opened this issue May 1, 2019 · 0 comments
Open
Labels
Business Scenario 具体业务场景 Vue Web 网络、性能、优化类

Comments

@amandakelake
Copy link
Owner

基础(必会)

参考链接:Intersection Observer API - Web API | MDN

思路

  • 创建LazyLoadImage类,全局只实例化一次,执行init方法
  • 每个img标签被创建时,自动将添加到观察者队列
    • 没进入视窗时,src被赋予了loading图片地址,真实的地址被保存在data-src属性中
    • 进入视窗后,从data-src属性中取出真正的地址,赋予给src属性,完成加载
  • 加载完图片后,把该img标签从观察者队列中删除,不再被观察

创建一个全局的LazyLoadImage

// 引入polyfill,解决兼容性问题
import 'intersection-observer'; 
IntersectionObserver.prototype['THROTTLE_TIMEOUT'] = 300;
const DefaultLoadingImage = '默认loading图片'

export default class LazyLoadImage {
  _observer: IntersectionObserver | null;
  _loadingImage: string;

  constructor(option: object = {}) {
    this._observer = null;
    // @ts-ignore
    this._loadingImage = option.loading || DefaultLoadingImage;
    this.init();
  }

  init() {
    this._observer = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        // 触发进入视窗条件,替换真正的图片链接到src属性上
        if (entry.isIntersecting) {
          // @ts-ignore
          const url = entry.target.getAttribute('data-src');
          // @ts-ignore
          entry.target.setAttribute('src', url);
          entry.target.setAttribute('data-src', '');
	  // 替换真正的线上地址后,取消对该元素的观察
          this._observer && this._observer.unobserve(entry.target);
        }
      })
    }, {
      root: null,
      rootMargin: "500px 200px 1000px 200px", // 扩大视窗范围,提前加载
      threshold: 0.1
    })
  }	

// 让每个img标签自行调用add方法,把自己添加到观察者队列中
  add(entry: any) {
    this._observer && this._observer.observe(entry.el);
  }
}

封装vue指令

// 全局只实例化一个类,实例执行init方法自己创建观察者队列
const lazyload = new LazyLoadImage();
// 让每个img标签自行调用add方法,把自己添加到观察者队列中
// 用法: <img v-lazy="图片地址" />
Vue.directive('lazy', {
    bind(el, binding) {
        el.setAttribute('data-src', binding.value);
        el.setAttribute('src', lazyload._loadingImage);
        lazyload.add({el: el, val: binding.value});
    }
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Business Scenario 具体业务场景 Vue Web 网络、性能、优化类
Projects
None yet
Development

No branches or pull requests

1 participant