Vue实现一个图片懒加载插件


Posted in Javascript onMarch 11, 2019

前言

图片懒加载是一个很常用的功能,特别是一些电商平台,这对性能优化至关重要。今天就用vue来实现一个图片懒加载的插件。 这篇博客采用“三步走”战略——Vue.use()、Vue.direction、Vue图片懒加载插件实现,逐步实现一个Vue的图片懒加载插件。

Vue.use()

就像开发jQuery插件要用$.fn.extent()一样,开发Vue插件我们要用Vue.use()。其实就是官方内部实现的一个方法,供广大开发者灵活开发属于自己的插件。只需要按照约定好的规则开发就行。

用法

安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。

该方法需要在调用 new Vue() 之前被调用。

当 install 方法被同一个插件多次调用,插件将只会被安装一次。

注:install方法或者被当做install方法的方法它的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象。

参考链接:

  • https://cn.vuejs.org/v2/api/#Vue-use
  • https://3water.com/article/146461.htm 

Vue.direction自定义指令

用法——全局注册和局部注册

全局注册

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
 // 当被绑定的元素插入到 DOM 中时……
 inserted: function (el) {
 // 聚焦元素
 el.focus()
 }
})

局部注册

directives: {
 focus: {
 // 指令的定义
 inserted: function (el) {
 el.focus()
 }
 }
}

钩子函数

一个指令定义对象可以提供如下几个钩子函数 (均为可选):

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
  • unbind:只调用一次,指令与元素解绑时调用。

钩子函数的参数

  • el:指令所绑定的元素,可以用来直接操作 DOM 。
  • binding:一个对象,包含以下属性:
  • name:指令名,不包括 v- 前缀。
  • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
  • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
  • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
  • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
  • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
  • vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

参考链接:https://cn.vuejs.org/v2/guide/custom-directive.html

Vue图片懒加载插件实现

思路:事先提供俩个空数组listenList(收集未加载的图片元素和资源)和imageCacheList(收集已加载的图片资源)。然后,判断图片是否到达可视区,如果到达,则用Image对象去加载资源图片,加载完毕后赋值给绑定元素的src让其显示。同时,将加载过的资源放入imageCacheList数组,用isAlredyLoad方法做个判断,防止之后相同的资源重复加载。如果没到达,则将元素和资源对象放到listenList数组,最后进行滚动监听。监听listenList数组中的元素是否可以加载资源。

插件的实现:

// 引入Vue构造函数
import Vue from 'vue'

var lazyload = {
 // Vue.use() 默认加载install,并且将Vue当做第一个参数传递过来
 install(vue,payload) {
 // 数组扩展移除元素
 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 defaultImage = payload.defaultImage || 'https://gw.alicdn.com/tps/i1/TB147JCLFXXXXc1XVXXxGsw1VXX-112-168.png';
 var errorImage = payload.errorImage || 'https://gw.alicdn.com/tps/i1/TB147JCLFXXXXc1XVXXxGsw1VXX-112-168.png';
 // 默认离可视区10px时加载图片
 var distanece = payload.scrollDistance || 10;
 // 收集未加载的图片元素和资源
 var listenList = [];
 // 收集已加载的图片元素和资源
 var imageCacheList = [];

 // 是否已经加载完成的图片
 const isAlredyLoad = (imageSrc) => {
 if(imageCacheList.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 - distance 距离可视区域还有distance像素
 if(top - distanece < window.innerHeight){ 
 var image = new Image();
 image.src = src;
 image.onload = function() {
 ele.src = src;
 imageCacheList.push(src);
 listenList.remove(item);
 }
 image.onerror = function() {
 ele.src = errorImage;
 imageCacheList.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 = defaultImage;

 //再看看是否可以显示此图片
 if(isCanShow(item)){
 return
 }

 //否则将图片地址和元素均放入监听的lisenList里
 listenList.push(item);
 
 //然后开始监听页面scroll事件
 onListenScroll();
 }

 Vue.directive('lazyload',{
 inserted: addListener,
 updated: addListener
 })
 }
}

export default lazyload;

插件的调用:

import Vue from 'vue'
import App from './App'
import router from './router'
import Lazyload from './common/js/lazyload'

// 参数均为可选
Vue.use(Lazyload,{
 scrollDistance: 15, // 距离可视区还有15px时开发加载资源
 defaultImage: '', // 资源图片未加载前的默认图片(绝对路径)
 errorImage:'' // 资源图片加载失败时要加载的资源(绝对路径)
})

参考链接:https://3water.com/article/112355.htm

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
浅析JavaScript中的隐式类型转换
Dec 05 Javascript
前台js对象在后台转化java对象的问题探讨
Dec 20 Javascript
js 阻止子元素响应父元素的onmouseout事件具体实现
Dec 23 Javascript
JS实现很酷的水波文字特效实例
Feb 26 Javascript
JS阻止事件冒泡行为和闭包的方法
Jun 16 Javascript
angular双向绑定模拟探索
Dec 26 Javascript
快速实现JS图片懒加载(可视区域加载)示例代码
Jan 04 Javascript
JS实现按钮控制计时开始和停止功能
Jul 27 Javascript
浅谈Node.js CVE-2017-14849 漏洞分析(详细步骤)
Nov 10 Javascript
jQuery实现ajax回调函数带入参数的方法示例
Jun 26 jQuery
vue-cli 首屏加载优化问题
Nov 06 Javascript
jquery实现弹窗(系统提示框)效果
Dec 10 jQuery
使用Jenkins部署React项目的方法步骤
Mar 11 #Javascript
vue基础之v-bind属性、class和style用法分析
Mar 11 #Javascript
配置eslint规范项目代码风格
Mar 11 #Javascript
vue基础之事件简写、事件对象、冒泡、默认行为、键盘事件实例分析
Mar 11 #Javascript
vue基础之事件v-onclick=&quot;函数&quot;用法示例
Mar 11 #Javascript
每天学点Vue源码之vm.$mount挂载函数
Mar 11 #Javascript
JavaScript中常用的简洁高级技巧总结
Mar 10 #Javascript
You might like
WAR3重制版DOTA 5V5初体验
2020/04/09 DOTA
php5 non-thread-safe和thread-safe这两个版本的区别分析
2010/03/13 PHP
非常经典的PHP文件上传类分享
2016/05/15 PHP
CI框架无限级分类+递归的实现代码
2016/11/01 PHP
thinkPHP显示不出验证码的原因与解决方法分析
2017/05/20 PHP
PDO::prepare讲解
2019/01/29 PHP
javascript 写类方式之八
2009/07/05 Javascript
$.ajax返回的JSON无法执行success的解决方法
2011/09/09 Javascript
js中parseFloat(参数1,参数2)定义和用法及注意事项
2013/01/27 Javascript
js循环改变div颜色具体方法
2013/06/25 Javascript
javaScript NameSpace 简单说明介绍
2013/07/18 Javascript
js实现不提交表单获取单选按钮值的方法
2015/08/21 Javascript
Bootstrap布局方式详解
2016/05/27 Javascript
使用plupload自定义参数实现多文件上传
2016/07/19 Javascript
使用JS 插件qrcode.js生成二维码功能
2017/02/20 Javascript
JS实现数组按升序及降序排列的方法
2017/04/26 Javascript
javaScript中封装的各种写法示例(推荐)
2017/07/03 Javascript
NodeJS父进程与子进程资源共享原理与实现方法
2018/03/16 NodeJs
vue + element-ui的分页问题实现
2018/12/17 Javascript
JavaScript学习笔记之DOM基础操作实例小结
2019/01/09 Javascript
jQuery利用cookie 实现本地收藏功能(不重复无需多次命名)
2019/11/07 jQuery
十分钟教你上手ES2020新特性
2020/02/12 Javascript
vue3.0自定义指令(drectives)知识点总结
2020/12/27 Vue.js
[04:17]DOTA2完美盛典,rOtk、BurNIng携手巴图演唱《倔强》
2017/11/28 DOTA
Python中用sleep()方法操作时间的教程
2015/05/22 Python
详解Python中的四种队列
2018/05/21 Python
python实现简单的学生管理系统
2021/02/22 Python
Luxplus荷兰:以会员价购买美容产品等,独家优惠
2019/08/30 全球购物
PHP如何调用MYSQL存储过程
2014/05/30 面试题
实用的简历自我评价
2014/03/06 职场文书
应届生求职自荐信范文
2014/04/07 职场文书
晋江市人民政府党组群众路线教育实践活动整改方案
2014/10/25 职场文书
委托书英文
2015/01/28 职场文书
信贷客户经理岗位职责
2015/04/09 职场文书
上班迟到检讨书
2015/05/06 职场文书
详解MySQL的半同步
2021/04/22 MySQL