<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 500px;
height: 600px;
overflow: scroll;
}
.box li {
width: 300px;
height: 200px;
}
img {
width: 300px;
height: 200px;
}
</style>
</head>
<body>
<div class="box" id="app">
<li v-for="(item,index) in imgs">
<img v-lazy="item.src" alt="" srcset="">
</li>
</div>
<script src="./vue-lazyload.js"></script>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let loading='http://127.0.0.1:5500/loading.gif'
Vue.use(VueLazyload,{
preLoad:1.3,
loading
})
let vm=new Vue({
el:'#app',
data() {
return {
name:'hahah',
imgs:[
{
src:'http://127.0.0.1:5500/1.jpg'
},
{
src:'http://127.0.0.1:5500/2.jpg'
},
{
src:'http://127.0.0.1:5500/3.jpg'
},
{
src:'http://127.0.0.1:5500/4.jpg'
},
{
src:'http://127.0.0.1:5500/5.jpg'
},
{
src:'http://127.0.0.1:5500/6.jpg'
},
{
src:'http://127.0.0.1:5500/7.jpg'
},
{
src:'http://127.0.0.1:5500/1.1.jpg'
},
{
src:'http://127.0.0.1:5500/2.1.jpg'
},
{
src:'http://127.0.0.1:5500/3.1.jpg'
},
{
src:'http://127.0.0.1:5500/4.1.jpg'
},
{
src:'http://127.0.0.1:5500/5.1.jpg'
},
{
src:'http://127.0.0.1:5500/6.1.jpg'
},
{
src:'http://127.0.0.1:5500/7.1.jpg'
},
]
}
},
})
</script>
</body>
</html>
function getscrollParent (el){
let parent = el.parentNode;
while(parent){
if(/(scroll)|(auto)/ .test(getComputedStyle(parent)['overflow'])){
return parent
}
parent = parent.parentNode
}
return parent
}
function loadImageAsync (src,resolve,reject){
let image = new Image()
image.src=src
image.onload = resolve;
image.onerror = reject;
}
const Lazy = (Vue)=>{
class ReactveListener {
constructor({el,src,options,elRender}){
this.el=el
this.src=src
this.options = options
this.state = {loading:false}
this.elRender=elRender
}
chechInView(){
let {top} = this.el.getBoundingClientRect()
return top < window.innerHeight * (this.options.preLoad || 1.3)
}
load(){
this.elRender(this,'loading')
loadImageAsync(this.src,()=>{
this.state.loading = true
this.elRender(this,'finish')
},()=>{
console.log('er')
this.elRender(this,'error')
})
}
}
return class LazyClass{
constructor(options){
this.options= options
this.bindHander = false
this.listenerQueue = []
}
add(el,bindings,vnode){
Vue.nextTick(()=>{
let scrollParent = getscrollParent(el)
if(scrollParent&&!this.bindHander){
this.bindHander = true
scrollParent.addEventListener('scroll',this.handerLazyload.bind(this))
}
const listener = new ReactveListener({
el,
src:bindings.value,
options:this.options,
elRender:this.elRender.bind(this)
})
this.listenerQueue.push(listener)
this.handerLazyload()
})
}
handerLazyload(){
this.listenerQueue.forEach(listener => {
if(!listener.state.loading){
let catIn = listener.chechInView()
catIn && listener.load()
}
});
}
elRender(listener,state){
console.log(state)
let el = listener.el
let src = ''
switch(state){
case 'loading' :
src = listener.options.loading || ''
break;
case 'error':
src = listener.options.error || ''
break;
default:
src = listener.src
break;
}
el.setAttribute('src',src)
}
}
}
const VueLazyload = {
install(Vue,options){
console.log('调用')
const LazyClass = Lazy(Vue)
const lazy = new LazyClass(options)
Vue.directive('lazy',{
bind:lazy.add.bind(lazy)
})
}
}