功能分析
- 懒加载的原理很简单,通过对滚动事件的监听,判断图片是否进入视口,如果没进入视口则不进行渲染
- 所以很明显,要实现一个懒加载,需要的函数有以下几个:
- 判断图片是否进入了可视区
- 监听滚动事件
- 检查图片是否已经加载过了(不要指望用户一定会一下滑过一整张图)
- 如果图片已经加载过了,不重复加载
准备工作:准备好所有功能函数
- 首先准备两个数组,一个放已经加载过的图片,一个放没有加载的图片;以及准备一个默认图片,如果滚动过快先显示默认图片
let init = {
default:'又不是不能用.jpg'
}
let futureList = [];
let cacheList = [];
if (!Array.prototype.remove) {
Array.prototype.remove = function (item) {
if (!this.length) {
return
}
let index = this.indexOf(item)
if (index > -1) {
this.splice(index, 1)
return this
}
}
}
const isLoad = (imgSrc) => {
if (cacheList.indexOf(imgSrc) > -1) {
return true
} else {
return false
}
}
const scrollIn = (item) => {
let el = item.el;
let src = item.src;
let top = el.getBoundingClientRect().top
let winHeight = window.innerHeight;
if (top + 5 < winHeight) {
let image = new Image()
image.src = src
image.onload = function () {
el.src = src
cacheList.push(src)
futureList.remove(item)
}
return true
} else {
return false
}
}
const listenScroll = () => {
window.addEventListener('scroll',function(){
let length = futureList.length
for(let i = 0; i < length; i++) {
scrollIn(futureList[i])
}
})
}
函数主体
const addListener = (el,binding) =>{
let imgSrc = bing.value
if(isLoad(imgSrc)){
el.src = imgSrc
return false
}
let item = {
el:el,
src:imgSrc
}
el.src = init default
if(scrollIn(item)) {
return
}
futureList.push(item)
listenScroll()
}
注册指令
- vue为我们提供了自定义指令时可以用到的一些钩子函数,这里用到的有两个:
- update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
- inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
- 注册
Vue.directive('lazyload', {
inserted: addListener,
updated: addListener
})
全部代码
export default (Vue) => {
let init = {
default: 'http://wx4.sinaimg.cn/large/a910d180gy1fwdiyoghi3j20to18uacp.jpg'
}
let futureList = [];
let cacheList = [];
const listenScroll = () => {
window.addEventListener('scroll', function () {
let length = futureList.length
for (let i = 0; i < length; i++) {
scrollIn(futureList[i])
}
})
}
const isLoad = (imgSrc) => {
if (cacheList.indexOf(imgSrc) > -1) {
return true
} else {
return false
}
}
const scrollIn = (item) => {
let el = item.el;
let src = item.src;
let top = el.getBoundingClientRect().top
let winHeight = window.innerHeight;
if (top + 5 < winHeight) {
let image = new Image()
image.src = src
image.onload = function () {
el.src = src
cacheList.push(src)
futureList.remove(item)
}
return true
} else {
return false
}
}
if (!Array.prototype.remove) {
Array.prototype.remove = function (item) {
if (!this.length) {
return
}
let index = this.indexOf(item)
if (index > -1) {
this.splice(index, 1)
return this
}
}
}
const addListener = (el, binding) => {
let imgSrc = binding.value
if (isLoad(imgSrc)) {
el.src = imgSrc
return false
}
let item = {
el,
src: imgSrc
}
el.src = init.default
if (scrollIn(item)) {
return
}
futureList.push(item)
listenScroll()
}
Vue.directive('lazyload', {
inserted: addListener,
updated: addListener
})
}