跳到主要内容

v-image-lazy-load

2023年11月03日
柏拉文
越努力,越幸运

一、认识


v-image-lazy-load 自定义指令完成图片懒加载

二、实现


2.1 定义

import { App } from 'vue';

export const ImageLazyLoad = {
install(app: App<Element>, _options: any) {
let defaultSrc = _options.default;
app.directive('imageLazyLoad', {
beforeMount(el, binding) {
ImageLazyLoad.init(el, binding.value, defaultSrc);
},
mounted(el) {
if ('IntersectionObserver' in window) {
ImageLazyLoad.observer(el);
} else {
ImageLazyLoad.listenerScroll(el);
}
}
});
},
init(el: any, value: string, defaultValue: string) {
el.setAttribute('data-src', value);
el.setAttribute('src', defaultValue);
},
observer(el: any) {
let intersectionObserver = new IntersectionObserver(entries => {
let realSrc = el.dataset.src;
if (entries[0].isIntersecting && realSrc) {
el.src = realSrc;
el.removeAttribute('data-src');
}
});
intersectionObserver.observe(el);
},
listenerScroll(el: any) {
const handler = ImageLazyLoad.throttle(ImageLazyLoad.load, 200);
ImageLazyLoad.load(el);
window.addEventListener('scroll', () => {
handler(el);
});
},
load(el: any) {
const realSrc = el.dataset.src;
let bodyHeight = document.documentElement.clientHeight;
let { top, bottom } = el.getBoundingClientRect();
if (top - bodyHeight < 0 && bottom > 0 && el.realSrc) {
el.src = realSrc;
el.removeAttribute('data-src');
}
},
throttle(fn: any, wait: number) {
let timer: any = null;
let previous: number = 0;

return function (...args: any[]) {
const context = this;
let now = +new Date();

if (now - previous < wait) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
previous = now;
fn.apply(context, args);
}, wait);
} else {
previous = now;
fn.apply(context, args);
}
};
}
};

2.2 安装

import App from './App.vue';
import { createApp } from 'vue';

import { ImageLazyLoad } from './directives/vImageLazyLoad';

import img1 from './assets/images/001.jpg';

const app = createApp(App);

app.use(ImageLazyLoad, { default: img1 });
app.mount('#app');

三、使用


<template>
<div>
<div class="img-list">
<div v-for="item in list" class="img-item">
<img v-image-lazy-load="item" :src="item" />
</div>
</div>
</div>
</template>

<script lang="ts" setup>
import { ref } from 'vue';

import img1 from './assets/images/001.jpg';
import img2 from './assets/images/002.jpg';
import img3 from './assets/images/003.jpg';
import img4 from './assets/images/004.jpg';
import img5 from './assets/images/005.jpg';
import img6 from './assets/images/006.jpg';
import img7 from './assets/images/007.jpg';
import img8 from './assets/images/008.jpg';
import img9 from './assets/images/009.jpg';
import img10 from './assets/images/010.jpg';
import img11 from './assets/images/011.jpg';

const list = ref([
img1,
img2,
img3,
img4,
img5,
img6,
img7,
img8,
img9,
img10,
img11
]);
</script>

<style scoped>
.img-list {
width: 100%;
}

.img-item {
width: 800px;
height: 400px;
}

.img-item img {
width: 100%;
height: 100%;
object-fit: contain;
}
</style>