当前位置: 首页 > news >正文

【懒加载】js实现懒加载、vue实现图片懒加载指令

懒加载

延迟加载,对于一个很长的页面,优先加载可视区域的内容,其他部分等进入可视区域时再加载

懒加载作用

是一种网页性能优化的方式,它能极大的提升用户体验。比如一个页面中有很多图片,但是首屏只出现几张,这时如果一次性把图片全部加载出来会影响性能。这时可以使用懒加载,页面滚动到可视区再加载。优化首屏加载。

图片懒加载

监听滚动条滚动事件,当视口的高度+滚动高度,大于图片所在位置举例顶部的偏移量时(也就是距离),加载图片资源

index.html

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><div style="height: 1200px;"></div><img src="https://ts2.cn.mm.bing.net/th?id=OIP-C.Fi0rA6s5NQ1VIlwp9IzhIgHaKe&w=210&h=297&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2"data-src="https://ts3.cn.mm.bing.net/th?id=OIP-C.D-43aYLc7We_sO_5ZSMIXgHaFj&w=288&h=216&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2" /><script>let img = document.getElementsByTagName("img");let num = img.length;let count = 0; lazyload();window.addEventListener('scroll', lazyload); function getTop(el) {var T = el.offsetTop;// 迭代地获取元素及其父元素相对于文档顶部的累积偏移量while (el = el.offsetParent) {T += el.offsetTop;}// 循环后 返回元素相对于文档顶部的总偏移量return T;}function lazyload() {//视口高度let viewHeight = document.documentElement.clientHeight || document.body.clientHeight;//滚动高度let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;for (let i = count; i < num; i++) {// 元素现在已经出现在视口中if (getTop(img[i]) < scrollTop + viewHeight) {// 如何图片等于默认图 则加载新图if (img[i].getAttribute("src") !== "https://ts2.cn.mm.bing.net/th?id=OIP-C.Fi0rA6s5NQ1VIlwp9IzhIgHaKe&w=210&h=297&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2") continue;img[i].src = img[i].getAttribute("data-src");count++;} else {break;}}}</script>
</body></html>

使用浏览器提供的getBoundingClientRect(),优化上述代码: lazyload修改如下:

getBoundingClientRect()用于获取元素相对于视口的位置信息

        function lazyload() {let viewHeight = document.documentElement.clientHeight || document.body.clientHeight;for (let i = count; i < num; i++) {// getBoundingClientRect() 用于获取元素相对于视口的位置信息// 当相对于视口位置 小于等于视口时说明图片已经可见了if (img[i].getBoundingClientRect().top < viewHeight) {if (img[i].getAttribute("src") !== "https://ts2.cn.mm.bing.net/th?id=OIP-C.Fi0rA6s5NQ1VIlwp9IzhIgHaKe&w=210&h=297&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2") continue;img[i].src = img[i].getAttribute("data-src");count++;} else {break;}}}

使用IntersectionObserver()再次优化上述代码

IntersectionObserver是浏览器原生提供的构造函数,用于查看某个元素是否进入了视口(viewport),用户能否看到该元素

修改上述代码:

    <script>let img = document.getElementsByTagName("img");const observer = new IntersectionObserver(changes => {console.log(changes)//changes 是被观察的元素集合for (let i = 0, len = changes.length; i < len; i++) {let change = changes[i];// 通过这个属性判断是否在视口中if (change.isIntersecting) {const imgElement = change.target;imgElement.src = imgElement.getAttribute("data-src");// IntersectionObserver 对象的一个方法,用于停止对指定元素的观察observer.unobserve(imgElement);}}})Array.from(img).forEach(item => {observer.observe(item)});</script>

内容懒加载:

一个页面有n条订单,每次可以给他显示10条,等用户拖动滚动条滚动到订单列表底部一段距离时再显示10条,直到加载完

<!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>span {display: block;}</style>
</head><body><div style="height: 1200px;">1</div><div class="box"><span>开始</span></div><script>let div = document.getElementsByClassName("box")[0];let lastSpanElement = div.querySelector('span:last-child');const observer = new IntersectionObserver(changes => {console.log(changes)//changes 是被观察的元素集合for (let i = 0, len = changes.length; i < len; i++) {let change = changes[i];// 通过这个属性判断是否在视口中if (change.isIntersecting) {for (let i = 0; i < 10; i++) {const spanElement = document.createElement('span');spanElement.textContent = `这是第 ${i + 1} 个<span>标签`;div.appendChild(spanElement);}observer.unobserve(lastSpanElement);lastSpanElement = div.querySelector('span:last-child');observer.observe(lastSpanElement)}}})observer.observe(lastSpanElement)</script>
</body></html>

详情可参考:(IntersectionObserver API详解_

IntersectionObserver 交叉观察器 - 简书 (jianshu.com)

IntersectionObserver

浏览器的5种观察器

app.directive

自定义全局指令,它有两种写法

// 注册(对象形式的指令)
// 所有生命周期都可
app.directive('my-directive', {/* 自定义指令钩子 */
})// 注册(函数形式的指令)
// 固定只在2个生命周期上触发, mounted 和 updated 
app.directive('my-directive', () => {/* ... */
})

 vue中install方法

可供我们开发新的自定义指令跟全局注册组件,第一个参数是vue的构造器,第二个参数是可选的选项对象

然后再开始编写扩展指令之图片懒加载指令

export default {install (app) {app.component(XtxSkeleton.name, XtxSkeleton)app.component(XtxCarousel.name, XtxCarousel)
+    defineDirective(app)}
}import defaultImg from '@/assets/images/200.png'
// 扩展指令
const defineDirective = (app) => {// 图片懒加载app.directive('lazyload', {mounted(el, binding) {const observer = new IntersectionObserver(([{ isIntersecting }]) => {if (isIntersecting) {// 停止观察observer.unobserve(el)el.onerror = () => {// 图片加载失败 设置默认图el.src = defaultImg}// binding 是对象,.value就是绑定指令的值el.src = binding.value}}, {//目标元素和根元素相交部分的比例达到该值的时候,//callback 函数将会被执行threshold: 0.01})// 开始观察observer.observe(el)}})
}

使用扩展的图片懒加载指令:

<img alt="" v-lazyload="goods.picture" />

扩展:

vue还有许多工具库,其中也有类似的api可以实现这种功能,列如:

useIntersectionObserver | VueUse

http://www.lryc.cn/news/137192.html

相关文章:

  • 微信小程序教学系列(7)
  • Android 9.0 kenel和frameworks中修改ram运行内存的功能实现
  • PHP实践:获取网络上图片的长宽以及图片类型
  • 使用 DPO 微调 Llama 2
  • 数据库——事务,事务隔离级别
  • 对《VB.NET通过VB6 ActiveX DLL调用PowerBasic及FreeBasic动态库》的改进
  • 【PHP】数据类型运算符位运算
  • 使用 Nacos 作为 Spring Boot 配置中心
  • 微服务 Eureka
  • Spring Boot 事务和事务传播机制
  • 计算机组成原理(巨巨巨基础篇)
  • C语言:选择+编程(每日一练Day7)
  • leetcode做题笔记93. 复原 IP 地址
  • HTTPS 中间人攻击
  • MATLAB打开excel读取写入操作例程
  • [C语言]分支与循环
  • 绘制区块链之链:解码去中心化、安全性和透明性的奇迹
  • 4G工业路由器的功能与选型!详解工作原理、关键参数、典型品牌
  • c与c++中struct的主要区别和c++中的struct与class的主要区别
  • mysql中char_length()和length()
  • Numpy学习笔记
  • LAMP配置与应用
  • Dockerfile搭建LNMP运行Wordpress平台
  • 数据库第十五课-------------非关系型数据库----------Redis
  • BM2 链表内指定区间反转,为什么链表要new一个结点?
  • SQL阶段性优化
  • 2023-08-22 Unity Shader 开发入门2 —— Shader 开发介绍
  • UE5 运行时捕捉外部窗口并嵌入到主窗口
  • uniapp 使用permission获取录音权限
  • 基于paddleocr的文档识别