Vue自定義圖片懶加載指令v-lazyload詳解
Vue是可以自定義指令的,最近學(xué)習(xí)過(guò)程中遇見(jiàn)了一個(gè)需要圖片懶加載的功能,最后參考了別人的代碼和思路自己重新寫(xiě)了一遍。以下將詳細(xì)介紹如何實(shí)現(xiàn)自定義指令v-lazyload。
先看如何使用這個(gè)指令:
<img v-lazyload="imageSrc" >
imageSrc是要加載的圖片的實(shí)際路徑。
為了實(shí)現(xiàn)這個(gè)指令,我們首先單獨(dú)建立一個(gè)文件,名字為lazyload.js.并填寫(xiě)基本的代碼,如下:
//Vue 圖片懶加載,導(dǎo)出模塊
export default (Vue , options = {})=>{
//初始化的選項(xiàng),default是未加載圖片時(shí)顯示的默認(rèn)圖片
var init = {
default: 'https://gw.alicdn.com/tps/i1/TB147JCLFXXXXc1XVXXxGsw1VXX-112-168.png'
}
//addListener為Vue指令的具體實(shí)現(xiàn)功能函數(shù),我們這里為所有使用v-lazyload的指令的元素添加監(jiān)聽(tīng)
//ele 是dom元素,binding是綁定的具體值,
//例如:<img v-lazyload="imageSrc" > ele是img binding是imageSrc
const addListenner = (ele,binding) =>{
}
//Vue自定義指令,lazyload為指令的名稱(chēng)
Vue.directive('lazyload',{
inserted:addListener,
updated:addListener
})
}
inserted 和 updated為Vue指令的執(zhí)行不同階段提供的鉤子函數(shù),查看Vue的官網(wǎng)可以看到一共有5個(gè)階段,
指令定義函數(shù)提供了幾個(gè)鉤子函數(shù)(可選):
bind: 只調(diào)用一次,指令第一次綁定到元素時(shí)調(diào)用,用這個(gè)鉤子函數(shù)可以定義一個(gè)在綁定時(shí)執(zhí)行一次的初始化動(dòng)作。
inserted: 被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用(父節(jié)點(diǎn)存在即可調(diào)用,不必存在于 document 中)。
update: 被綁定元素所在的模板更新時(shí)調(diào)用,而不論綁定值是否變化。通過(guò)比較更新前后的綁定值,可以忽略不必要的模板更新(詳細(xì)的鉤子函數(shù)參數(shù)見(jiàn)下)。
componentUpdated: 被綁定元素所在模板完成一次更新周期時(shí)調(diào)用。
unbind: 只調(diào)用一次, 指令與元素解綁時(shí)調(diào)用。
這里我們只用inserted和updated就夠了。
接下來(lái)我們具體實(shí)現(xiàn)addListener的實(shí)現(xiàn)。我們的具體思路如下:
1、先看看這個(gè)圖片是否需要懶加載。有兩種情況,一是圖片還沒(méi)到達(dá)可視區(qū)域,二是圖片已經(jīng)加載過(guò)了。
2、然后監(jiān)聽(tīng)窗口的scroll事件,判斷哪些圖片可以進(jìn)行懶加載了。
這里我們需要一個(gè)需要進(jìn)行監(jiān)聽(tīng)需要懶加載的圖片列表和一個(gè)需要記錄已經(jīng)加載過(guò)得圖片列表。另外為了方便數(shù)組的操作,我們加一個(gè)數(shù)組的remove方法。
繼續(xù)我們的代碼。
//Vue 圖片懶加載
export default (Vue , options = {})=>{
//數(shù)組item remove方法
if(!Array.prototype.remove){
Array.prototype.remove = function(item){
if(!this.length) return
var index = this.indexOf(item);
if( index > -1){
this.splice(index,1);
return this
}
}
}
var init = {
default: 'https://gw.alicdn.com/tps/i1/TB147JCLFXXXXc1XVXXxGsw1VXX-112-168.png'
}
//需要進(jìn)行監(jiān)聽(tīng)的圖片列表,還沒(méi)有加載過(guò)得
var listenList = [];
//已經(jīng)加載過(guò)得圖片緩存列表
var imageCatcheList = [];
//是否已經(jīng)加載過(guò)了
const isAlredyLoad = (imageSrc) => {
}
//檢測(cè)圖片是否可以加載,如果可以則進(jìn)行加載
const isCanShow = (item) =>{
};
//添加監(jiān)聽(tīng)事件scroll
const onListenScroll = () =>{
}
//Vue 指令最終的方法
const addListener = (ele,binding) =>{
//綁定的圖片地址
var imageSrc = binding.value;
//如果已經(jīng)加載過(guò),則無(wú)需重新加載,直接將src賦值
if(isAlredyLoad(imageSrc)){
ele.src = imageSrc;
return false;
}
var item = {
ele:ele,
src:imageSrc
}
//圖片顯示默認(rèn)的圖片
ele.src = init.default;
//再看看是否可以顯示此圖片
if(isCanShow(item)){
return
}
//否則將圖片地址和元素均放入監(jiān)聽(tīng)的lisenList里
listenList.push(item);
//然后開(kāi)始監(jiān)聽(tīng)頁(yè)面scroll事件
onListenScroll();
}
Vue.directive('lazyload',{
inserted:addListener,
updated:addListener
})
}
接下來(lái)就幾個(gè)空方法的實(shí)現(xiàn)了。
isAlredyLoad ,判斷是否已經(jīng)加載過(guò)了這個(gè)圖片
const isAlredyLoad = (imageSrc) => {
if(imageCatcheList.indexOf(imageSrc) > -1){
return true;
}else{
return false;
}
}
isCanShow 圖片是否進(jìn)入可視區(qū)域,如果已經(jīng)進(jìn)入則進(jìn)行加載
//檢測(cè)圖片是否可以加載,如果可以則進(jìn)行加載
const isCanShow = (item) =>{
var ele = item.ele;
var src = item.src;
//圖片距離頁(yè)面頂部的距離
var top = ele.getBoundingClientRect().top;
//頁(yè)面可視區(qū)域的高度
var windowHeight = window.innerHight;
//top + 10 已經(jīng)進(jìn)入了可視區(qū)域10像素
if(top + 10 < window.innerHeight){
var image = new Image();
image.src = src;
image.onload = function(){
ele.src = src;
imageCatcheList.push(src);
listenList.remove(item);
}
return true;
}else{
return false;
}
};
onListenScroll監(jiān)聽(tīng)滾動(dòng)事件,并且檢測(cè)是否進(jìn)入可視區(qū)域。
const onListenScroll = () =>{
window.addEventListener('scroll',function(){
var length = listenList.length;
for(let i = 0;i<length;i++ ){
isCanShow(listenList[i]);
}
})
}
最終我們的代碼如下:
//Vue 圖片懶加載
export default (Vue , options = {})=>{
if(!Array.prototype.remove){
Array.prototype.remove = function(item){
if(!this.length) return
var index = this.indexOf(item);
if( index > -1){
this.splice(index,1);
return this
}
}
}
var init = {
lazyLoad: false,
default: 'https://gw.alicdn.com/tps/i1/TB147JCLFXXXXc1XVXXxGsw1VXX-112-168.png'
}
var listenList = [];
var imageCatcheList = [];
const isAlredyLoad = (imageSrc) => {
if(imageCatcheList.indexOf(imageSrc) > -1){
return true;
}else{
return false;
}
}
//檢測(cè)圖片是否可以加載,如果可以則進(jìn)行加載
const isCanShow = (item) =>{
var ele = item.ele;
var src = item.src;
//圖片距離頁(yè)面頂部的距離
var top = ele.getBoundingClientRect().top;
//頁(yè)面可視區(qū)域的高度
var windowHeight = window.innerHight;
//top + 10 已經(jīng)進(jìn)入了可視區(qū)域10像素
if(top + 10 < window.innerHeight){
var image = new Image();
image.src = src;
image.onload = function(){
ele.src = src;
imageCatcheList.push(src);
listenList.remove(item);
}
return true;
}else{
return false;
}
};
const onListenScroll = () =>{
window.addEventListener('scroll',function(){
var length = listenList.length;
for(let i = 0;i<length;i++ ){
isCanShow(listenList[i]);
}
})
}
//Vue 指令最終的方法
const addListener = (ele,binding) =>{
//綁定的圖片地址
var imageSrc = binding.value;
//如果已經(jīng)加載過(guò),則無(wú)需重新加載,直接將src賦值
if(isAlredyLoad(imageSrc)){
ele.src = imageSrc;
return false;
}
var item = {
ele:ele,
src:imageSrc
}
//圖片顯示默認(rèn)的圖片
ele.src = init.default;
//再看看是否可以顯示此圖片
if(isCanShow(item)){
return
}
//否則將圖片地址和元素均放入監(jiān)聽(tīng)的lisenList里
listenList.push(item);
//然后開(kāi)始監(jiān)聽(tīng)頁(yè)面scroll事件
onListenScroll();
}
Vue.directive('lazyload',{
inserted:addListener,
updated:addListener
})
}
使用時(shí)需要在主文件中引入這個(gè)文件,并且vue.use();
import LazyLoad from 'lazyLoad.js' Vue.use(LazyLoad);
并且在需要懶加載的圖片上均按照如下使用v-lazyload指令即可
<img v-lazyload="imageSrc" >
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
淺談vue實(shí)現(xiàn)數(shù)據(jù)監(jiān)聽(tīng)的函數(shù) Object.defineProperty
本篇文章主要介紹了淺談vue實(shí)現(xiàn)數(shù)據(jù)監(jiān)聽(tīng)的函數(shù) Object.defineProperty,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
Vue綁定class和綁定內(nèi)聯(lián)樣式的實(shí)現(xiàn)方法
本文主要介紹了Vue綁定class和綁定內(nèi)聯(lián)樣式的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
vue.js內(nèi)置組件之keep-alive組件使用
keep-alive是Vue.js的一個(gè)內(nèi)置組件。這篇文章主要介紹了vue.js內(nèi)置組件之keep-alive組件使用,需要的朋友可以參考下2018-07-07
基于vue2.0實(shí)現(xiàn)的級(jí)聯(lián)選擇器
這篇文章主要介紹了基于vue2.0實(shí)現(xiàn)的級(jí)聯(lián)選擇器,基于Vue的級(jí)聯(lián)選擇器,可以單項(xiàng),二級(jí), 三級(jí)級(jí)聯(lián),多級(jí)級(jí)聯(lián),有興趣可以了解一下2017-06-06
基于Vue 實(shí)現(xiàn)一個(gè)中規(guī)中矩loading組件
這篇文章主要介紹了基于Vue 實(shí)現(xiàn)一個(gè)中規(guī)中矩loading組件,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04
使用Vue3實(shí)現(xiàn)倒計(jì)時(shí)器及倒計(jì)時(shí)任務(wù)的完整代碼
文章介紹了如何使用Vue3和Element-plus開(kāi)發(fā)一個(gè)倒計(jì)時(shí)器和倒計(jì)時(shí)任務(wù)管理界面,倒計(jì)時(shí)器具備手動(dòng)設(shè)置、開(kāi)始、暫停和重啟功能,文章還提供了倒計(jì)時(shí)器的完整代碼,包括HTML、JavaScript和CSS部分,感興趣的朋友一起看看吧2024-11-11
vue實(shí)現(xiàn)點(diǎn)擊圖片放大效果
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)點(diǎn)擊圖片放大效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
解決Vue開(kāi)發(fā)中對(duì)話框被遮罩層擋住的問(wèn)題
在Vue的開(kāi)發(fā)中,一旦我們用到對(duì)話框,經(jīng)常出現(xiàn)的問(wèn)題是對(duì)話框被遮罩層擋住,怎么來(lái)解決這個(gè)問(wèn)題呢?下面小編給大家?guī)?lái)了Vue開(kāi)發(fā)中對(duì)話框被遮罩層擋住的問(wèn)題及解決方法,一起看看吧2018-11-11

