图片懒加载及Vue自定义图片懒加载指令

news2024/10/6 21:34:10

文章目录

    • 监听滚动的方式
    • 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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/416123.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文推荐:DCSAU-Net,更深更紧凑注意力U-Net

这是一篇23年发布的新论文&#xff0c;论文提出了一种更深、更紧凑的分裂注意力的U-Net&#xff0c;该网络基于主特征守恒和紧凑分裂注意力模块&#xff0c;有效地利用了底层和高层语义信息。 DCSAU-Net 1、架构 DCSAU-Net 的编码器首先使用 PFC 策略从输入图像中提取低级语义…

适用于 Windows 11/1 0电脑的 8 款最佳免费数据恢复软件

在这个数字办公时代&#xff0c;我们总是在电脑前工作&#xff0c;处理海量数据&#xff0c;存储重要文件。然而&#xff0c;系统崩溃、病毒攻击或人为错误都会导致极度绝望的数据丢失。此时&#xff0c;专业的数据备份和恢复工具就是不幸者的救命稻草。因此&#xff0c;这篇文…

深入剖析Compose布局, 一步步教你打造自适应UI界面

理解Compose布局 Compose 是一种基于声明式编程的 Android UI 工具包&#xff0c;它将可组合的 UI 要素视为函数&#xff0c;并使用 Kotlin DSL 进行构建和组合。Compose 还提供了相应的布局系统和一组用于嵌套和组合 UI 要素的基本函数。 Compose 的核心布局系统由两个部分组…

Windows使用Dockers+battery historian踩坑记

1、首先&#xff0c;需要翻墙。 2、然后安装Dockers&#xff0c;网上好多博客说安装Docker Toolbox&#xff0c;我亲测无效&#xff0c;卸载后安装Docker for Windows&#xff0c;安装完成后打开&#xff0c;会提示&#xff1a; Hardware assisted virtualization and data e…

Promise这样理解更简单

一、Promise小白怎么用&#xff1f;从一个故事开始吧 1、先来一段废话故事 您是一名在古老迷失城市中探险的冒险家。您身处一间装饰华丽的房间中&#xff0c;四周布满了古老的壁画和雕塑。您发现有两个通道分别通向不同的方向&#xff0c;分别是&#xff1a;一个黑暗的通道和…

Hive源码阅读环境准备

源码地址 hive源码地址在github或gitee均可以下载&#xff0c;如果没有vpn工具&#xff0c;使用gitee网速更快点。 github地址为: https://github.com:edingbrugh/hive.gitgitee地址如下: https://gitee.com/apache/hive.git环境要求 本地或远程已经安装hivejdk 8maven 3.6…

高权限注入跨库注入

简介 上篇文章中我们讲述了如何进行手工注入&#xff0c;也通过墨者学院的靶场&#xff0c;真实的感受了SQL注入的感觉。这篇文章我们将继续介绍SQL注入。 高权限注入 含义 世界上有千千万万的网站&#xff0c;我们也都知道网站需要部署在服务器上&#xff0c;但是如果一台…

C++基础知识-----命名空间

本期开始我们来对C进行学习 目录 1.C关键字 2.命名空间 3.C的输入与输出 1.C关键字 C总计63个关键字&#xff0c;C语言32个关键字 asmdoifreturntrycontinueautodoubleinlineshorttypedefforbooldynamic_castintsignedtypeidpublicbreakelselongsizeoftypenamethrowcase…

摘得重磅奖项,发表精彩演讲,深度参编报告!美创闪耀CSA GCR大会

4月13日&#xff0c;第六届云安全联盟大中华区大会在上海举办&#xff0c;大会由联合国数字安全联盟、上海市经济和信息化委员会、上海市委网络安全和信息化委员会办公室、上海市普陀区人民政府指导&#xff0c;云安全联盟大中华区主办。 作为零信任数据安全践行者&#xff0c;…

java银行ATM机模拟系统dzkf94

目录 摘要 I Abstract II 第1章 绪论 1 1.1 ATM简介 1 1.2 ATM发展 1 1.3 开发意义 1 1.4 论文的组成 1 1.5 本章小结 2 第2章 系统分析 3 2.1 功能需求分析 3 2.2 业务流程分析 4 2.3 数据流程分析 5 2.4 本章小结 7 第3章 系统开发技…

车载网络 - Autosar网络管理 - 常用缩写

为了方便大家日常工作中的使用和交流&#xff0c;每块专业规范或者文章中&#xff0c;都会有或多或少的缩写使用&#xff0c;然而如果一段时间没使用&#xff0c;经常会忘记这些缩写到底代表的是什么意思&#xff0c;为了方便后续内容的介绍&#xff0c;也为了我自己后面忘记后…

【数据分析之道-NumPy(四)】numpy广播机制

文章目录 专栏导读1、广播机制2、一维数组和二维数组的广播3、二维数组和三维数组的广播4、标量和数组的广播5、形状不兼容的数组不能进行广播专栏导读 ✍ 作者简介:i阿极,CSDN Python领域新星创作者,专注于分享python领域知识。 ✍ 本文录入于《数据分析之道》,本专栏针对…

MySQL---数据类型

文章目录前言一、数据类型分类二、数值类型1.tinyint类型2.bit类型三、小数类型1.float2. decimal三、字符串类型1.char2.varchar3.char和varchar比较四、日期和时间类型五、enum和set我们如何找到性别是男或者女呢?我们如何找到爱好有rapper呢?总结前言 正文开始!!! 一、数…

MyBatis 批量插入的正确姿势

近日,项目中有一个耗时较长的Job存在CPU占用过高的问题,经排查发现,主要时间消耗在往MyBatis中批量插入数据。mapper configuration是用foreach循环做的,差不多是这样。 这个方法提升批量插入速度的原理是,将传统的: INSERT INTO `table1` (`field1`, `field2`) VALUES …

Linux服务器怎么关闭防火墙?

Linux服务器怎么关闭防火墙&#xff1f; 在很多情况下&#xff0c;防火墙都会组织一些端口号的通讯。 比如我们的tomcat&#xff0c;nginx&#xff0c;redis明明安装的没问题&#xff0c;但在外部就是访问不了&#xff0c;那很有可能就是防护墙的原因了。我是艾西&#xff0c;…

protobuf编码格式解析

示例 假如定义一个如下的protobuf类型 message Person {required string user_name 1;optional int64 favorite_number 2;repeated string interests 3; }将其赋值为: user_name : "Martin" favorite_number : 1337 interests:"daydrea…

pyLoad远程代码执行漏洞复现(CVE-2023-0297)

1、产品简介 pyLoad是一个用 Python 编写的免费和开源下载管理器&#xff0c;可用于NAS、下一代路由器、无头家庭服务器以及任何能够连接到互联网并支持 Python 编程语言的设备。 2、漏洞概述 pyLoad 存在代码注入漏洞&#xff0c;未经身份验证的攻击者可以通过滥用 js2py 功能…

c/c++:类型限定符,printf输出格式,putchar,scanf,getchar

c/c&#xff1a;类型限定符&#xff0c;printf输出格式&#xff0c;putchar&#xff0c;scanf&#xff0c;getchar 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;此时学会c的话&#xff0c; 我所知道的周边的会c的同学&am…

结构方程模型(SEM)高阶应用系列

结构方程模型&#xff08;Structural Equation Modeling&#xff09;是分析多变量间因果关系的利器&#xff0c;在众多学科领域具有巨大应用潜力。我们前期推出的《基于R语言结构方程模型》通过结构方程原理介绍、结构方程全局和局域估计、模型构建和调整、潜变量分析、复合变量…

docker-compose安装prometheus告警系统

docker-compose安装Prometheus一、概述一、docker-compose二、配置文件一、概述 本文只有监控与告警的安装、告警发送、发送模版的配置。没有数据展示监控数据UI工具 一、docker-compose 1&#xff09;docker-compose.yaml version: 3.0 services:#1.prometheusprometheus:…