浏览器实现图片懒加载(适合小白,简单高效)

方案一:视窗高度与图片元素距内容顶部判定+防抖优化实现

1.封装防抖

export default  (func: ()=>void, delay: number) => {
    // 防抖
    // 返回一个函数,该函数在delay时间内只执行一次
    let timer: number | null = null;
    return () => {
        if (timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(() => {
            func()
        }, delay);
    };
}

2.组件中应用
<template>
  <div class="lazyDiv">
        <img v-for="item in imagesList" :key="item._id" :data-src="item.src" src="../../public/favicon.ico" alt="" class="lazyload">
  </div>
</template>
​
<script setup>
    import {onMounted, ref} from 'vue'
    import axios from 'axios'
    import useDebounce from '@/hooks/useDebounce';
    axios.defaults.baseURL = 'http://localhost:3000'
​
    let imagesList = ref([])
    let getImages = async()=>{
        let {data:{code,imageList}} = await axios.get('/getImages')
        if(code === 200){
            imagesList.value = imageList
            console.log(imagesList.value);
        }
    }
    //获取所有img标签
    const images = document.getElementsByTagName('img')
​
    //方案一:依据相应图片元素距离页面展示内容顶部距离(image.getBoundingClientRect().top)是否大于浏览器当前内容区窗口高(window.innerHeight)判定
     let lazyload = ()=>{
        console.log('lazyload触发');
         [...images].forEach(image=>{
             //下行获取目标图片image元素距离页面展示内容顶部距离
             const topDistance = image.getBoundingClientRect().top
             //图片距内容顶部高于视窗高度做判定
                 if(topDistance < window.innerHeight){  //成立更换img的src属性
                     const data_src = image.getAttribute('data-src')
                     image.setAttribute('src', data_src)
                 }
         })
     }
​
    onMounted(()=>{
        getImages()
        window.addEventListener('scroll', useDebounce(lazyload, 500))
        window.onload = ()=>{
            lazyload()
        }
    })
    
</script>
​
<style lang="less">
    .lazyDiv{
        width: 100%;
        height: 100%;
​
        img{
            display: block;
            margin: 15px;
            width: 180px;
            height: 150px
        }
    }
</style>

方案二:浏览器内置的IntersectionObserver

原理:

通过当图片与浏览器视口产生交叉区域,执行事件,并可以在事件执行之后清除监听(即成功加载图片后不会再触发)

组件中应用
<template>
  <div class="lazyDiv">
        <img v-for="item in imagesList" :key="item._id" :data-src="item.src" src="../../public/favicon.ico" alt="" class="lazyload">
  </div>
</template>
​
<script setup>
    import {onMounted, ref} from 'vue'
    import axios from 'axios'
    axios.defaults.baseURL = 'http://localhost:3000'
​
    let imagesList = ref([])
    let getImages = async()=>{
        let {data:{code,imageList}} = await axios.get('/getImages')
        if(code === 200){
            imagesList.value = imageList
        }
    }
    //获取所有img标签
    const images = document.getElementsByTagName('img')
​
    //方案二:当图片与浏览器视口产生交叉区域,执行事件,并可以在事件执行之后清除监听(即成功加载图片后不会再触发)
    const lazyLoad2 = ()=>{     //先执行同步代码逐个事件监听,所以这里callback才可以遍历正常
        const callback = (entries)=>{
            entries.forEach(entry=>{
                // console.log('entry===',entry);
                if(entry.isIntersecting){   //如果产生交叉区域
                    const data_src = entry.target.getAttribute('data-src')  //获取相应img标签属性,并做src属性赋值
                    entry.target.setAttribute('src', data_src)
                    console.log('执行了一次监听');
                    observer.unobserve(entry.target)    //执行监听后移除监听
                }
            })
        }
        const observer = new IntersectionObserver(callback);    //创建一个观察者对象
        [...images].forEach(image=>{
            observer.observe(image)     //遍历并监视每张图片
        })
    }
​
​
    onMounted(()=>{
        getImages()
        window.onload = ()=>{
            lazyLoad2()
        }
    })
    
</script>
​
<style lang="less">
    .lazyDiv{
        width: 100%;
        height: 100%;
​
        img{
            display: block;
            margin: 15px;
            width: 180px;
            height: 150px
        }
    }
</style>
  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值