文章目录
- 监听滚动的方式
- IntersectionObserver方式
- 自定义图片懒加载vue指令1
- 自定义图片懒加载vue指令2
- lazyLoadImage.js
- main.js中注册指令
- 组件中使用
学习链接:
前端必会的图片懒加载
vue自定义指令实现图片懒加载
监听滚动的方式
- img的src先都用一张默认的图片,data-src属性为真实图片地址
- 当图片出现在可视区范围内时,把src属性换成data-src属性,就完成了
- 缺点:一当发生滚动事件时,就发生了大量的循环和判断操作判断图片是否可视区里
- 补充一点:当把img的src从默认的图片换成真实的图片url后,在真实图片未加载完成前,还会一直是默认图片
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}
img {
width: 200px;
height: 200px;
object-fit: cover;
}
</style>
<script>
window.onload = function () {
window.addEventListener('scroll', loadImg)
function loadImg() {
console.log('-----'); // 每一次滚动都会执行,可能滚动条只滚动了一小段距离,但这个函数执行了很多次
let imgs = document.querySelectorAll('img')
// console.dir(imgs[0].getAttribute('data-src'));
// console.dir(imgs[0].getAttribute('src'));
for (let i = 0; i < imgs.length; i++) {
if(imgs[i].getBoundingClientRect().top < window.innerHeight - 200) { // 也可以这样判断:imgs[i].offsetTop <= window.scrollY + window.innerHeight - 200
imgs[i].setAttribute('src', imgs[i].getAttribute('data-src'))
}
}
}
loadImg() // 刚开始的时候,也要加载一次看看有没有图片就正好满足显示条件
}
</script>
</head>
<body>
<img src="./img/img0.jpg" data-src="./img/post1.jpg">
<img src="./img/img0.jpg" data-src="./img/post2.jpg">
<img src="./img/img0.jpg" data-src="./img/post3.jpg">
<img src="./img/img0.jpg" data-src="./img/post4.jpg">
<img src="./img/img0.jpg" data-src="./img/post5.jpg">
<img src="./img/img0.jpg" data-src="./img/post6.jpg">
</body>
</html>
IntersectionObserver方式
- IntersectionObserver是浏览器原生提供的构造函数
- 使用IntersectionObserver的observe方法,来观察某个元素
- 使用IntersectionObserver的unobserve方法,来取消观察某个元素
- 页面一加载的时候,就会返回所有被观察的元素它们的情况,注意是所有。此后,当某个元素出现在可视区时(从不在可视区到在可视区那个时刻),或者某个离开时可视区时(从在可视区到不在可视区的那个时刻),都会触发回调函数,回调函数传过来的参数就会告诉使用者哪些元素正在离开可视区,哪些元素正在进入可视区。
- 除了回调函数这个参数外,还可以指定一个配置对象,配置对象中可以配置threshold,它表示目标元素与根元素的交叉比例,可以是单一的 number 也可以是 number 数组,比如,[0, 0.25, 0.5, 0.75, 1]就表示当目标元素 0%、25%、50%、75%、100% 可见时,会触发回调函数。详细解释:IntersectionObserver API详解
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}
img {
width: 200px;
height: 200px;
object-fit: cover;
}
</style>
<script>
window.onload = function () {
function callback(entries) {
console.log(entries); /* [IntersectionObserverEntry,..] */
for(let i of entries) {
if(i.isIntersecting) { /* 当元素出现在可视窗口时 */
let img = i.target
img.setAttribute('src',img.getAttribute('data-src'))
observer.unobserve(img) /* 已经看见的图片, 取消观察 */
}
}
}
/* IntersectionObserver是浏览器原生提供的构造函数 */
const observer = new IntersectionObserver(callback);
let imgs = document.querySelectorAll('img')
/* 可以为每一张图片绑定一个观察器 */
for (let i of imgs) {
observer.observe(i);
}
}
</script>
</head>
<body>
<img src="./img/img0.jpg" data-src="./img/post1.jpg">
<img src="./img/img0.jpg" data-src="./img/post2.jpg">
<img src="./img/img0.jpg" data-src="./img/post3.jpg">
<img src="./img/img0.jpg" data-src="./img/post4.jpg">
<img src="./img/img0.jpg" data-src="./img/post5.jpg">
<img src="./img/img0.jpg" data-src="./img/post6.jpg">
</body>
</html>
自定义图片懒加载vue指令1
<style>
img {
width: 200px;
height: 200px;
object-fit: cover;
display: block;
}
</style>
<template>
<div>
LazyImg
<br/>
<img src="@/assets/post1.jpg" v-lazy alt="">
<img src="@/assets/post2.jpg" v-lazy alt="">
<img src="@/assets/post3.jpg" v-lazy alt="">
<img src="@/assets/post4.jpg" v-lazy alt="">
<img src="@/assets/post5.jpg" v-lazy alt="">
<img src="@/assets/post6.jpg" v-lazy alt="">
</div>
</template>
<script>
import img0 from '@/assets/img0.jpg'
console.log(img0);
console.log(require('@/assets/img0.jpg'));
export default {
name: 'lazyImg',
directives: {
lazy: {
bind(el,binding) {
el.setAttribute("data-src",el.getAttribute("src"))
el.setAttribute("src", img0)
let observer = new IntersectionObserver(entries=>{
for(let i of entries) {
if(i.isIntersecting) {
el.setAttribute('src',el.getAttribute("data-src") )
observer.unobserve(el)
}
}
})
observer.observe(el)
}
}
},
components: {
}
}
</script>
自定义图片懒加载vue指令2
lazyLoadImage.js
const lazyLoadImage = defaultImage => {
let windowHeight = document.documentElement.clientHeight || document.body.clientHeight//可视区域高
function throttle(fn, delay) {//节流
let timeout = null
return (...args) => {
if (timeout) return
timeout = setTimeout(() => {
fn.apply(this, args)
timeout = null
}, delay);
}
}
function loadImage(el) {//加载图片
return () => {
let top = el.getBoundingClientRect().top
let bottom = el.getBoundingClientRect().bottom
if (top - windowHeight < 0 && bottom > 0&&el.hasAttribute('data-src')) {//图片出现在可视区域内开始加载图片
el.src = el.getAttribute('data-src')
el.removeAttribute('data-src')
}
}
}
return {
bind(el, binding) {
console.log(defaultImage);
let realSrc = el.src
el.src = defaultImage
el.setAttribute('data-src', realSrc)
},
inserted(el) {
loadImage(el)()//显示初始(首屏)图片
window.addEventListener('scroll', throttle(loadImage(el), 500))//每滚动500毫秒加载一次图片
}
}
}
const install = {
install(vue, defaultImage) {
//v-lazy
vue.directive('lazy1', lazyLoadImage(defaultImage))
}
}
export default install
main.js中注册指令
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import '@/assets/css/base.css'
import '@/assets/iconfont/iconfont.css'
import 'animate.css'
Vue.config.productionTip = false
Vue.use(ElementUI);
import lazyLoadImage from './utils/lazyLoadImage'
const defaultImage=require('@/assets/img0.jpg')//默认占位图片
Vue.use(lazyLoadImage,defaultImage)
new Vue({
router,
render: h => h(App)
}).$mount('#app')
组件中使用
<style>
img {
width: 200px;
height: 200px;
object-fit: cover;
display: block;
}
</style>
<template>
<div>
LazyImg
<br/>
<img src="@/assets/post1.jpg" v-lazy1 alt="">
<img src="@/assets/post2.jpg" v-lazy1 alt="">
<img src="@/assets/post3.jpg" v-lazy1 alt="">
<img src="@/assets/post4.jpg" v-lazy1 alt="">
<img src="@/assets/post5.jpg" v-lazy1 alt="">
<img src="@/assets/post6.jpg" v-lazy1 alt="">
</div>
</template>
<script>
export default {
name: 'lazyImg',
components: {
}
}
</script>