JavaScript实现图片懒加载与预加载的代码详解
作者:六个点
引言
图片懒加载与预加载是前端优化中比较常见的方法,也是前端面试中会被问到的问题。懒加载就是当你打开一个页面时,没有出现在屏幕中的图片先不加载,等滑到该图片位置时再加载,而预加载就是一次性把图片加载完。
如果不做懒加载和预加载,浏览器的回流重绘很快,而图片的加载是需要发送网络请求的,当图片一百甚至一千张时,一次性发很多请求就会导致网络的堵塞,影响用户体验,接下来就让我们来实现一下懒加载以及预加载的效果。
懒加载
懒加载原理就是监听屏幕滚动事件,然后判断图片是否出现在屏幕内,等图片要出现在屏幕内再加载。可以使用js中的getBoundingClientRect()
方法,获取元素的集合属性,打印如下。
<body> <img src="" data-src="https://t7.baidu.com/it/u=1732966997,2981886582&fm=193&f=GIF" alt=""> <script> let img = document.querySelector('img') let rect = img.getBoundingClientRect() // 获取元素几何属性 console.log(rect); </script> </body>
left:左边框到窗口左边的距离,right:右边框到窗口左边的距离,bottom:下边框到窗口上边的距离,top:上边框到窗口上边的距离。
然后判断图片是否在容器内,图片的top小于窗口的高度,图片的bottom大于0。
为了让图片先不展示,就不能把图片的url放在src属性上,于是我们可以在img标签中自己定义一个属性data-src
,将图片地址放进去,然后当图片要展示时,令图片的src等于data-src属性,展示过后的图片再移除掉data-src
属性。
<img src="" data-src="https://t7.baidu.com/it/u=17329669972981886582&fm=193&f=GIF" alt="">
<script> let height = window.innerHeight function lazyLoad() { const imgs = document.querySelectorAll('[data-src]') // console.log(imgs); for (let i = 0; i < imgs.length; i++) { let rect = imgs[i].getBoundingClientRect() // 获取元素的集合属性 if (rect.bottom > 0 && rect.top < height) { imgs[i].src = imgs[i].getAttribute('data-src') imgs[i].onload = function () { // 图片被浏览器加载完毕 imgs[i].src = imgs[i].getAttribute('src') } imgs[i].removeAttribute('data-src') } } } lazyLoad() window.addEventListener('scroll', lazyLoad) </script>
当然里面的imgs[i].src = imgs[i].getAttribute('data-src')
可以换成如下:
// imgs[i].src = imgs[i].getAttribute('data-src') // imgs[i].onload = function () { // 图片被浏览器加载完毕 // imgs[i].src = imgs[i].getAttribute('src') // } // 换成 let newImg = new Image() newImg.src = imgs[i].getAttribute('data-src') // 读取 url newImg.onload = function () { // 图片被浏览器加载完毕 imgs[i].src = newImg.getAttribute('src') }
目的是为了将图片的加载过程异步化,以此来减轻主线程的压力。这是通过创建一个新的Image
对象,然后设置其src
属性来预加载图片,一旦图片加载完成(onload
事件触发),再将图片的src
属性设置到原来的img
元素上。
效果如下:
预加载
用户一打开页面,全部图片先加载,然后后用户滑动就会非常地丝滑,但是就会导致同一时间加载图片过多,对服务器压力过大。
原理:在加载页面的同时,创建第二个线程去加载图片,当图片加载完毕后,将图片资源交给第一个线程去展示,从而实现图片的预加载。
代码如下;
<div id="pic"></div> <script> let pic = document.getElementById('pic') let arr = [xxxxx] // 图片资源 // 创建一个新的线程 const worker = new Worker('worker.js') // 将数据发送给子线程 worker.postMessage(arr) </script>
worker函数是js自带的一个函数,作用就是创建一个新线程,但是这个新线程不能操作dom结构。这两个线程可以通信,通过postMessage进行通讯。
然后worker.js里面去加载图片,直接通过http请求去加载资源,回来的是blob类型的文件。
// worker.js self就是worker self.onmessage = function (e) { // console.log(e.data); // 传过来的图片资源 // 将数组中的地址资源加载出来 let arr = e.data; for (let i = 0; i < arr.length; i++) { let xhr = new XMLHttpRequest(); xhr.open("get", arr[i], true); xhr.responseType = 'blob' // 文件类型 xhr.send(); xhr.onload = function () { if (xhr.readyState === 4 && xhr.status === 200) { // console.log(xhr.response); self.postMessage(xhr.response); //将图片发送给主线程 } } } }
然后主线程去接收资源再进行渲染;
<body> <div id="pic"></div> <script> let pic = document.getElementById('pic') let arr = [xxxxx] // 图片资源 // 创建一个新的线程 const worker = new Worker('worker.js') // 将数据发送给子线程 worker.postMessage(arr) // 接收子线程发送的数据 worker.onmessage = function (e) { console.log(e.data); const img = new Image() // console.log(window.URL.createObjectURL(e.data)); img.src = window.URL.createObjectURL(e.data) pic.appendChild(img) } </script> </body>
window.URL.createObjectURL(e.data)
是window自带的方法,作用就是将blob资源转换成url。
小结
- 懒加载原理:当页面加载完毕后,判断在可视区域内的图片先加载,当用户滚动时,判断图片是否进入可视区域,如果进入可视区,则将图片的src替换为真实图片路径,从而实现懒加载的原理。
- 预加载原理:在加载页面的同时,开一个新线程去加载图片,当图片加载完毕后,将图片资源交给主线程去展示,从而实现图片的预加载。
以上就是JavaScript实现图片懒加载与预加载的代码详解的详细内容,更多关于JavaScript图片懒加载与预加载的资料请关注脚本之家其它相关文章!