Vue是能夠自定義指令的,最近學習過程當中碰見了一個須要圖片懶加載的功能,最後參考了別人的代碼和思路本身從新寫了一遍。如下將詳細介紹如何實現自定義指令v-lazyload。vue
先看如何使用這個指令:數組
<img v-lazyload="imageSrc" >複製代碼
imageSrc是要加載的圖片的實際路徑。緩存
爲了實現這個指令,咱們首先單獨創建一個文件,名字爲lazyload.js.並填寫基本的代碼,以下:bash
//Vue 圖片懶加載,導出模塊
export default (Vue , options = {})=>{
//初始化的選項,default是未加載圖片時顯示的默認圖片
var init = {
default: 'https://gw.alicdn.com/tps/i1/TB147JCLFXXXXc1XVXXxGsw1VXX-112-168.png'
}
//addListener爲Vue指令的具體實現功能函數,咱們這裏爲全部使用v-lazyload的指令的元素添加監聽
//ele 是dom元素,binding是綁定的具體值,
//例如:<img v-lazyload="imageSrc" > ele是img binding是imageSrc複製代碼
const addListenner = (ele,binding) =>{
}
//Vue自定義指令,lazyload爲指令的名稱
Vue.directive('lazyload',{
inserted:addListener,
updated:addListener
})
}複製代碼
inserted 和 updated爲Vue指令的執行不一樣階段提供的鉤子函數,查看Vue的官網能夠看到一共有5個階段,dom
指令定義函數提供了幾個鉤子函數(可選):函數
bind
: 只調用一次,指令第一次綁定到元素時調用,用這個鉤子函數能夠定義一個在綁定時執行一次的初始化動做。學習
inserted
: 被綁定元素插入父節點時調用(父節點存在便可調用,沒必要存在於 document 中)。ui
update
: 被綁定元素所在的模板更新時調用,而不論綁定值是否變化。經過比較更新先後的綁定值,能夠忽略沒必要要的模板更新(詳細的鉤子函數參數見下)。this
componentUpdated
: 被綁定元素所在模板完成一次更新週期時調用。spa
unbind
: 只調用一次, 指令與元素解綁時調用。
這裏咱們只用inserted和updated就夠了。
接下來咱們具體實現addListener的實現。咱們的具體思路以下:
一、先看看這個圖片是否須要懶加載。有兩種狀況是不須要加載的,一是圖片還沒到達可視區域,二是圖片已經加載過了。
二、而後監聽窗口的scroll事件,判斷哪些圖片能夠進行加載了。
這裏咱們須要一個須要進行監聽須要懶加載的圖片列表和一個須要記錄已經加載過得圖片列表。另外爲了方便數組的操做,咱們加一個數組的remove方法。
繼續咱們的代碼。
//Vue 圖片懶加載
export default (Vue , options = {})=>{
//數組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'
}
//須要進行監聽的圖片列表,尚未加載過得
var listenList = [];
//已經加載過得圖片緩存列表
var imageCatcheList = [];
//是否已經加載過了
const isAlredyLoad = (imageSrc) => {
}
//檢測圖片是否能夠加載,若是能夠則進行加載
const isCanShow = (item) =>{
};
//添加監聽事件scroll
const onListenScroll = () =>{
}
//Vue 指令最終的方法
const addListener = (ele,binding) =>{
//綁定的圖片地址
var imageSrc = binding.value;
//若是已經加載過,則無需從新加載,直接將src賦值
if(isAlredyLoad(imageSrc)){
ele.src = imageSrc;
return false;
}
var item = {
ele:ele,
src:imageSrc
}
//圖片顯示默認的圖片
ele.src = init.default;
//再看看是否能夠顯示此圖片
if(isCanShow(item)){
return
}
//不然將圖片地址和元素均放入監聽的lisenList裏
listenList.push(item);
//而後開始監聽頁面scroll事件
onListenScroll();
}
Vue.directive('lazyload',{
inserted:addListener,
updated:addListener
})
}複製代碼
接下來就幾個空方法的實現了。
isAlredyLoad ,判斷是否已經加載過了這個圖片
複製代碼
const isAlredyLoad = (imageSrc) => {
if(imageCatcheList.indexOf(imageSrc) > -1){
return true;
}else{
return false;
}
}複製代碼
isCanShow 圖片是否進入可視區域,若是已經進入則進行加載
//檢測圖片是否能夠加載,若是能夠則進行加載
const isCanShow = (item) =>{
var ele = item.ele;
var src = item.src;
//圖片距離頁面頂部的距離
var top = ele.getBoundingClientRect().top;
//頁面可視區域的高度
var windowHeight = window.innerHight;
//top + 10 已經進入了可視區域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監聽滾動事件,而且檢測是否進入可視區域。複製代碼
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;
}
}
//檢測圖片是否能夠加載,若是能夠則進行加載
const isCanShow = (item) =>{
var ele = item.ele;
var src = item.src;
//圖片距離頁面頂部的距離
var top = ele.getBoundingClientRect().top;
//頁面可視區域的高度
var windowHeight = window.innerHight;
//top + 10 已經進入了可視區域10像素
if(top + 10 < window.innerHeight){ //obj.right-100 < windowWidth
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(){ //最好兼容左右的滑動touchend
var length = listenList.length;
for(let i = 0;i<length;i++ ){
isCanShow(listenList[i]);
}
})
}
//Vue 指令最終的方法
const addListener = (ele,binding) =>{
//綁定的圖片地址
var imageSrc = binding.value;
//若是已經加載過,則無需從新加載,直接將src賦值
if(isAlredyLoad(imageSrc)){
ele.src = imageSrc;
return false;
}
var item = {
ele:ele,
src:imageSrc
}
//圖片顯示默認的圖片
ele.src = init.default;
//再看看是否能夠顯示此圖片
if(isCanShow(item)){
return
}
//不然將圖片地址和元素均放入監聽的lisenList裏
listenList.push(item);
//而後開始監聽頁面scroll事件
onListenScroll();
}
Vue.directive('lazyload',{
inserted:addListener,
updated:addListener
})
}複製代碼
使用時須要在主文件中引入這個文件,而且vue.use();
import LazyLoad from 'lazyLoad.js'
Vue.use(LazyLoad);複製代碼
而且在須要懶加載的圖片上均按照以下使用v-lazyload指令便可
<img v-lazyload="imageSrc" >複製代碼