Vue自定义指令v-lazyload实现图片懒加载详解
本文详细介绍如何在Vue中通过自定义指令实现图片懒加载功能。通过定义v-lazyload指令,利用inserted和updated钩子函数监听滚动事件,判断图片是否进入可视区域后再进行加载,从而提升页面性能。
Vue自定义指令v-lazyload实现图片懒加载详解
Vue支持自定义指令的开发。在近期的学习实践中,遇到了图片懒加载的需求,经过参考现有代码与思路后,重新编写了相关实现。下文将详细阐述如何构建自定义指令v-lazyload。
首先展示该指令的具体使用方式:
<img v-lazyload="imageSrc" >
其中,imageSrc代表需要加载的图片实际路径。
为实现该指令,首先需单独创建一个名为lazyload.js的文件,并编写基础代码,如下所示:
//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个阶段:
指令定义函数提供了多个可选的钩子函数:
bind:仅调用一次,在指令首次绑定到元素时执行,可用于定义绑定时的初始化动作。
inserted:当被绑定元素插入父节点时调用(只要父节点存在即可,无需存在于document中)。
update:当被绑定元素所在模板更新时调用,无论绑定值是否变化。通过比较更新前后的绑定值,可忽略不必要的模板更新(详细钩子函数参数见下文)。
componentUpdated:当被绑定元素所在模板完成一次更新周期时调用。
unbind:仅调用一次,在指令与元素解绑时执行。
在本实现中,仅需使用inserted和updated两个钩子即可满足需求。
接下来具体实现addListener函数。核心思路如下:
1、判断图片是否需要进行懒加载。存在两种情况:一是图片尚未进入可视区域,二是图片已经加载完成。
2、监听窗口的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){
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;
//如果已经加载过,则无需重新加载,直接将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" >
以上为本文全部内容,希望对各位的学习有所帮助,也欢迎大家继续支持本站。
怎么在Vue3项目中集成轻量级JS文本编辑器
2026-11-03 12:21:35
Vue.js官网怎么切换Vue 2与Vue 3版本文档?避免看错版本指南
2026-11-03 08:08:08
ElementUI el-switch 开关组件使用详解与高级应用
2026-10-31 15:21:18
Element UI 表格行按钮点击加载与状态管理实现
2026-10-31 14:12:32
fullCalendar日历插件高级用法与源码修改实战
2026-10-31 10:19:16
