衆所周知,對於頁面內容比較豐富的網站,dom的解析會很複雜,這樣就會致使首屏加載過慢,對於圖片很豐富的網站,咱們知道可使用圖片懶加載來提升網站的響應速度,我在個人另一篇文章中寫過,有興趣的點擊這裏。像淘寶、京東等等的首頁都是通過懶加載處理的,他們會先渲染出骨架,而後懶加載的區域出如今了可視範圍的時候再把骨架替換爲真實的內容。vue
骨架: node
真實內容:
api
這樣就避免首頁一次性加載過多的內容瀏覽器須要渲染過多的dom致使的卡慢, 同時圖片也懶加載了,避免下載圖片致使的dom渲染阻塞,可謂一舉而兩得,那麼在vue中,咱們怎麼作懶加載呢?這裏分享下我作的項目當中,利用vue的mixin作的懶加載。瀏覽器
關於vue mixin,我想你們都知道vue mixin的做用,我的以爲它最大的用處就是共享一些數據data
和方法methods
,從而實現代碼重用。居於它的做用,我選擇mixin做爲實現懶加載的手段,全部須要懶加載的模塊,都導入懶加載所須要的mixin。bash
咱們知道vue的v-if
能夠決定是否要渲染該組件,因此咱們利用v-if來控制懶加載的組件,若是這個組件不在可視區域,則將其設爲false,或者讓它渲染骨架,當組件出如今可視區域的時候再去渲染真實的dom。dom
判斷組件是否出如今可視區域有兩種手段:
1、是利用元素的getBoundingClientRect
方法獲取元素所處的位置,而後判斷top屬性是否大於0到window.innerHeight之間,而且須要監聽頁面的scroll事件,不斷進行上述判斷,想要了解更多的,請閱讀我開頭說的圖片懶加載實現方式。
2、利用新特性IntersectionObserver
,這個特性不須要咱們去監聽滾動事件,只要元素出如今視線,就會觸發可見的事件post
if ("IntersectionObserver" in window) {
let lazyCompObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
// 元素可見
if (entry.intersectionRatio > 0) {
// TODO 進行一些元素可見後的一些操做,同時該元素不須要被observe了
lazyCompObserver.unobserve(entry.target)
}
})
})
if(this.$el.nodeType === 1) {
// 須要observe的元素
lazyCompObserver.observe(this.$el)
}
}
複製代碼
綜上所述,咱們實現懶加載的mixin是這樣寫的網站
// lazy-load mixin
import {throttle, getClientHeight} from 'tool/tool'
export default {
data() {
return {
isShow: false,
_throttleFn: null
}
},
methods: {
inViewShow() {
if(this.isShow) {
document.removeEventListener('scroll', this._throttleFn, false)
return
}
// 不支持IntersectionObserver api的狀況下判斷圖片是否出如今可視區域內
let { $el } = this
const rect = $el.getBoundingClientRect()
// 出如今視野的時候加載元素
if(0 < rect.top && rect.top < getClientHeight()) {
this.isShow = true
}
}
},
mounted() {
// 支持IntersectionObserver的使用這個api
if ("IntersectionObserver" in window) {
let lazyCompObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.intersectionRatio > 0) {
this.isShow = true
lazyCompObserver.unobserve(entry.target)
// 當元素可見時,若是須要回調,則執行
this.onVisible && this.onVisible()
}
})
})
if(this.$el.nodeType === 1) {
lazyCompObserver.observe(this.$el)
}
} else {
// 不支持的使用getBoundingClientRect和scroll來判斷
this.inViewShow()
this._throttleFn = throttle(this.inViewShow)
document.addEventListener('scroll', this._throttleFn, false)
}
}
}
// 調用
<template>
<li v-if="isShow">
.....
</li>
</template>
<script>
import lazyLoad from 'mixins/lazy-load'
export default {
mixins: [lazyLoad],
methods: {
onVisible() {
console.log('元素可見了')
}
}
}
</script>
複製代碼
效果就是這樣 第一個li是可見的,第二個li不可見,因此不渲染。ui
有不對或者改正的地方,忘各位留言指正。this