图片懒加载
记录一次笔试题
实现一个图片懒加载事件
- 使用节流函数,时延1s
- 加载完全部图片时销毁监听事件事件
首先我们先实现一个基础的图片懒加载方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Lazy Loading with Throttled Scroll</title> <style> img { display: block; width: 100%; height: 300px; margin-bottom: 20px; } </style> </head> <body> <img src="https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B" alt=""> <div id="app"> <img :id="image.id" v-for="image in images" :data-src="image.src" :key="image.id" :alt="image.alt" /> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> new Vue({ el: '#app', data() { return { images: [ { id: 1, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 2, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 3, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 4, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 5, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 6, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 7, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 8, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 9, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 10, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 11, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 12, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, ] }; }, mounted() { // 监听滚动事件,并使用loadImages函数作为回调函数 window.addEventListener('scroll', () => { this.loadImages(); }); // 初始化加载可见的图片 this.$nextTick(() => { this.loadImages(); }) }, methods: { // 加载图片 loadImages() { const windowHeight = window.innerHeight; const windowWidth = window.innerWidth; for (let i = 0; i < this.images.length; i++) { const image = this.images[i]; const imgElement = this.$el.querySelector(`img[id="${image.id}"]`); const imgRect = imgElement.getBoundingClientRect(); if (imgRect.top < windowHeight && imgRect.left < windowWidth) { // 图片进入视口,加载真实图片源 imgElement.src = image.src } } } }, }); </script> </body> </html>
第二步,增加节流函数
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Lazy Loading with Throttled Scroll</title> <style> img { display: block; width: 100%; height: 300px; margin-bottom: 20px; } </style> </head> <body> <img src="https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B" alt=""> <div id="app"> <img :id="image.id" v-for="image in images" :data-src="image.src" :key="image.id" :alt="image.alt" /> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> new Vue({ el: '#app', data() { return { images: [ { id: 1, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 2, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 3, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 4, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 5, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 6, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 7, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 8, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 9, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 10, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 11, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 12, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, ], throttledLoadImages: null, }; }, mounted() { this.throttledLoadImages = this.throttle(this.loadImages, 1000); // 监听滚动事件,并使用节流的loadImages函数作为回调函数 window.addEventListener('scroll', () => { this.throttledLoadImages(); }); // 初始化加载可见的图片 this.$nextTick(() => { this.loadImages(); }) }, methods: { // 加载图片 loadImages() { const windowHeight = window.innerHeight; const windowWidth = window.innerWidth; for (let i = 0; i < this.images.length; i++) { const image = this.images[i]; const imgElement = this.$el.querySelector(`img[id="${image.id}"]`); const imgRect = imgElement.getBoundingClientRect(); if (imgRect.top < windowHeight && imgRect.left < windowWidth) { // 图片进入视口,加载真实图片源 imgElement.src = image.src } } }, // 创建节流函数 throttle(func, delay) { let startTime = 0 return function(...args){ const nowTime = new Date().getTime() const waitTime = delay - (nowTime - startTime) if(waitTime <= 0){ func.apply(this, args) startTime = nowTime } } } }, }); </script> </body> </html>
第三步,添加标志位,表示是否所有图片都已加载完成
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Lazy Loading with Throttled Scroll</title> <style> img { display: block; width: 100%; height: 300px; margin-bottom: 20px; } </style> </head> <body> <img src="https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B" alt=""> <div id="app"> <img :id="image.id" v-for="image in images" :data-src="image.src" :key="image.id" :alt="image.alt" /> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> new Vue({ el: '#app', data() { return { images: [ { id: 1, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 2, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 3, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 4, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 5, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 6, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 7, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 8, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 9, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 10, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 11, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, { id: 12, src: 'https://uploadfiles.nowcoder.com/images/20240315/677424810_1710464757879/FECD76F09C4EFFA7102ECDBC1795FB3B', alt: '' }, ], throttledLoadImages: null, }; }, mounted() { // 创建节流的loadImages函数 this.throttledLoadImages = this.throttle(this.loadImages, 1000); // 监听滚动事件,并使用节流的loadImages函数作为回调函数 window.addEventListener('scroll', () => { this.throttledLoadImages(); }); // 初始化加载可见的图片 this.$nextTick(() => { this.loadImages(); }) }, beforeDestroy() { // 组件销毁前移除滚动事件监听器 // window.removeEventListener('scroll', this.throttledLoadImages); }, methods: { // 加载图片 loadImages() { const windowHeight = window.innerHeight; const windowWidth = window.innerWidth; let allImagesLoaded = true; // 添加标志位,表示是否所有图片都已加载完成 for (let i = 0; i < this.images.length; i++) { const image = this.images[i]; const imgElement = this.$el.querySelector(`img[id="${image.id}"]`); const imgRect = imgElement.getBoundingClientRect(); if (imgRect.top < windowHeight && imgRect.left < windowWidth && !this.imageLoaded(image)) { // 图片进入视口,加载真实图片源 image.loaded = true; imgElement.src = image.src } if (!this.imageLoaded(image)) { allImagesLoaded = false; // 如果存在未加载完成的图片,则将标志位置为false } } if (allImagesLoaded) { // 如果所有图片都已加载完成,则移除滚动事件监听器 console.log('销毁事件') window.removeEventListener('scroll', this.throttledLoadImages); } }, // 检查图片是否已加载 imageLoaded(image) { return image.loaded; }, // 创建节流函数 throttle(func, delay) { let startTime = 0 return function (...args) { const nowTime = new Date().getTime(); const waitTime = delay - (nowTime - startTime); // 距离上次执行函数的时间间隔 if (waitTime <= 0) { func.apply(this, args) console.log("执行") startTime = nowTime } }; }, }, }); </script> </body> </html>