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

news/2024/7/10 2:34:05 标签: javascript, 前端, 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()用于获取元素相对于视口的位置信息

javascript">        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),用户能否看到该元素

修改上述代码:

javascript">    <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的构造器,第二个参数是可选的选项对象

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

javascript">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)
        }
    })
}

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

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

扩展:

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

useIntersectionObserver | VueUse


http://www.niftyadmin.cn/n/4964601.html

相关文章

网络电子词典

一、项目要求&#xff1a; 1. 登录注册功能&#xff0c;不能重复登录&#xff0c;重复注册 2. 单词查询功能 3. 历史记录功能&#xff0c;存储单词&#xff0c;意思&#xff0c;以及查询时间 4. 基于TCP&#xff0c;支持多客户端连接 5. 采用数据库保存用户信息与历史记录…

python接口自动化之如何使用requests库发送http请求

前言 今天笔者想和大家来聊聊python接口自动化如何使用requests库发送http请求&#xff0c;废话呢笔者就不多说了&#xff0c;直接进入正题。 一、requests库 什么是Requests &#xff1f;Requests 是⽤Python语⾔编写&#xff0c;基于urllib&#xff0c;采⽤Apache2 Licensed…

driver‘s license exam 4

driver‘s license exam 1_spencer_tseng的博客-CSDN博客 driver‘s license exam 2_spencer_tseng的博客-CSDN博客 driver‘s license exam 3_spencer_tseng的博客-CSDN博客 driver‘s license exam 4_spencer_tseng的博客-CSDN博客 car indicator light_spencer_tseng的博…

Redis下载与安装

文章目录 Redis简介下载&#xff0c;安装和配置&#xff08;cmd&#xff09;图形化工具 Redis 简介 下载&#xff0c;安装和配置&#xff08;cmd&#xff09; 开启redis服务 1.在解压出来的文件夹中打开cmd 2.输入 redis-server.exe redis.windows.conf即可开启服务 可以看到…

我是大运火炬手丨民营企业家极米钟波:大运精神激励企业不断创新、追求极致

7月26日&#xff0c;成都第31届世界大学生夏季运动会火炬传递成都站第五传递日活动&#xff0c;在成都3所高校以及东安湖体育公园继续进行。极米科技股份有限公司&#xff08;以下简称“极米科技”&#xff09;董事长钟波是第92棒火炬手。 火炬手钟波 大学求学在成都&#xff…

HDLBits-Verilog学习记录 | Verilog Language-Basics(2)

文章目录 9.Declaring wires | wire decl10. 7458 chip 9.Declaring wires | wire decl problem:Implement the following circuit. Create two intermediate wires (named anything you want) to connect the AND and OR gates together. Note that the wire that feeds the …

探索Kotlin K2编译器和Java编译器的功能和能力

文章首发地址 Kotlin K2编译器是Kotlin语言的编译器&#xff0c;负责将Kotlin源代码转换为Java字节码或者其他目标平台的代码。K2编译器是Kotlin语言的核心组件之一&#xff0c;它的主要功能是将Kotlin代码编译为可在JVM上运行的字节码。 K2编译器快速介绍 编译过程&#xff…

美创科技“签”手柠檬文才学堂,共推高校数据安全建设

近日&#xff0c;由柠檬文才学堂联合中国教育在线、东北财经大学网络教育学院共同主办的“三教统筹下高校继续教育数字化转型研讨”顺利召开。 国内高等院校&#xff08;高职院校&#xff09;继续教育分管领导&#xff0c;继续教育学院领导及继续教育信息化、教学教务管理、课程…