解析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的簡要設計思想能夠如圖所示


後記

理清總體思路,分析源碼就很清晰了,切忌陷入無窮的細節中。

相關文章
相關標籤/搜索