解析vue-lazyload的设计思想

以前业务中碰到了一个需求,这个需求若是彻底硬编码在程序中的话,能够实现需求,可是复用性基本等于零,并且与业务代码混在一块儿,若是之后需求变好了很是很差修改。

仔细思考过解耦性和优雅性以后,发现能够借鉴一下以前使用过的vue-lazyload的设计思路,此文章即解析一下vue-lazyload的简要设计思路。
html

vue-lazyload解决了什么问题?

能够想象一个网页打开有成百上千的图片须要加载,页面会变得很是的卡顿,此时若是只是可视区域的图片加载,其余的图片能够暂时有一个占位loading图,等滚动它们到可视区域时再去请求真实图片而且替换就行了。很好,vue-lazyload插件就是解决此类问题的,对vue插件的写法不熟悉的能够先看一下 vue插件

vue-lazyload设计简析

解析以前能够先思考一下若是本身写一个图片懒加载的工具,会如何实现呢?首先最明显的是须要一个检查图片dom元素是否在浏览器可视区域内的方法checkInView,而后须要给全部图片的滚动父元素绑定一个滚动事件的监听方法scrollHandler,因此大概的思路图为:


其实上图就已经实现了一个最最基本的图片懒加载的思路了,稍加修饰就能够写出可运行的代码。

接下来带着这个基本思路来看vue-layload的实现.
vue

src/index.js
git


能够看到提供了两种指令使用方式和两种组件使用方式,我主要分析v-lazy的指令在vue2版本的实现,其余的能够自行分析,原理相通。

能够看出来经过Lazy和LazyClass获得了lazy这个对象,v-lazy指令对应的几个回调函数:bind、update、componentUpdated和unbind分别绑定的是lazy对象的add、update、lazyLoadHandler和remove方法。github

接下来看lazy对象是如何生成的:

src/lazy.js
数组


能够看到lazy.js文件导出了一个方法,该方法又返回了一个Lazy类,这么写的缘由是为了造成闭包来继续在Lazy类中引用Vue。下面看Lazy类的构造函数:
浏览器


能够看到构造函数里面初始化了一大堆的配置和变量,一个函数lazyLoadHandler以及setMode来判断是否使用observer来检测dom可见( IntersectionObserver

顺着刚刚src/index.js的思路继续往下看指令bind回调函数发生了什么:闭包

src/lazy.js



能够看到对于每一个添加了v-lazy指令的dom元素,都会先找到它的scrollParent元素(其实就是一直向上遍历到它overflow=auto或scroll的祖先元素);而后会生成一个newListener对象,而且把newListener加到ListenerQueue数组中;最后调用_addListenerTarget方法。

接着看_addListenerTarget方法发生了什么:
dom

src/lazy.js
ide


能够看到将scrollParent元素放入了TargetQueue,而且调用了_initListen方法

继续看_initListen方法:

src/lazy.js
函数


能够看到给scrollParent监听了this.options.ListenEvents里面的全部事件,事件回调函数为lazyLoadHandler。

在前面已经说过了lazyLoadHandler的初始化:

src/lazy.js


lazyLoadHandler方法就是_lazyLoadHandler加了一个节流包装后返回的函数。

继续看_lazyLoadHandler的实现:

src/lazy.js


能够看到_lazyLoadHandler方法里是遍历了ListenerQueue数组,而且调用每一个listener的checkInView,若是checkInView返回true则调用listener.load;此时其实能够猜到checkInView是在检查该listener对应的dom元素是否在可视区域内,listener.load方法是在请求真正的image。

因此梳理一下,vue-lazyload的简要设计思想能够如图所示


后记

理清总体思路,分析源码就很清晰了,切忌陷入无穷的细节中。

相关文章
相关标签/搜索