性能优化篇--优化首屏体验

优化首屏体验

Lazy-Load 初探

掘金首页采用了懒加载策略。当我们的页面并未滚动至包含图片的 div 元素所在的位置时,它的样式是这样的:

js 复制代码
<div data-v-b2db8566=""  
    data-v-009ea7bb=""  
    data-v-6b46a625=""  
    data-src="https://user-gold-cdn.xitu.io/2018/9/27/16619f449ee24252?imageView2/1/w/120/h/120/q/85/format/webp/interlace/1"  
    class="lazy thumb thumb"  
    style="background-image: none; background-size: cover;">  
</div>
  • 我们注意到 style 内联样式中,背景图片设置为了 none。也就是说这个 div 是没有内容的,它只起到一个占位的作用。
  • 一旦我们通过滚动使得这个 div 出现在了可见范围内,那么 div 元素的内容就会发生变化,呈现如下的内容:
js 复制代码
style="background-image: url(&quot;https://user-gold-cdn.xitu.io/2018/9/27/16619f449ee24252?imageView2/1/w/120/h/120/q/85/format/webp/interlace/1&quot;); background-size: cover;"

一起写一个 Lazy-Load

html 复制代码
<!DOCTYPE html>  
<html lang="en">  
<head>  
<meta charset="UTF-8">  
<meta >  
<meta http-equiv="X-UA-Compatible" content="ie=edge">  
<title>Lazy-Load</title>  
<style>  
    .img {  
        width: 200px;  
        height:200px;  
        background-color: gray;  
    }  
    .pic {  
        // 必要的img样式  
    }  
</style>  
</head>  
<body>  
    <div class="container">  
        <div class="img">  
            // 注意我们并没有为它引入真实的src  
            <img class="pic" alt="加载中" data-src="./images/1.png">  
        </div>  
        <div class="img">  
            <img class="pic" alt="加载中" data-src="./images/2.png">  
        </div>  
        <div class="img">  
            <img class="pic" alt="加载中" data-src="./images/3.png">  
        </div>  
        <div class="img">  
            <img class="pic" alt="加载中" data-src="./images/4.png">  
        </div>  
        <div class="img">  
            <img class="pic" alt="加载中" data-src="./images/5.png">  
        </div>  
        <div class="img">  
            <img class="pic" alt="加载中" data-src="./images/6.png">  
        </div>  
        <div class="img">  
            <img class="pic" alt="加载中" data-src="./images/7.png">  
        </div>  
        <div class="img">  
            <img class="pic" alt="加载中" data-src="./images/8.png">  
        </div>  
        <div class="img">  
            <img class="pic" alt="加载中" data-src="./images/9.png">  
        </div>  
        <div class="img">  
            <img class="pic" alt="加载中" data-src="./images/10.png">  
        </div>  
    </div>  
</body>  
</html>
  • 在懒加载的实现中,有两个关键的数值:一个是当前可视区域的高度 ,另一个是元素距离可视区域顶部的高度。
  • 当前可视区域的高度 , 在和现代浏览器及 IE9 以上的浏览器中,可以用 window.innerHeight 属性获取。在低版本 IE 的标准模式中,可以用 document.documentElement.clientHeight 获取,这里我们兼容两种情况:
js 复制代码
const viewHeight = window.innerHeight || document.documentElement.clientHeight

而元素距离可视区域顶部的高度 ,我们这里选用 getBoundingClientRect() 方法来获取返回元素的大小及其相对于视口的位置。对此 MDN 给出了非常清晰的解释:

返回的DOMRect 对象包含了一组用于描述边框的只读属性---------left、top、right 和 bottom,单位为像素。除了 width 和 height 外的属性都是相对于视口的左上角位置而言的。

Lazy-Load 方法的实现:

html 复制代码
<script>  
    // 获取所有的图片标签  
    const imgs = document.getElementsByTagName('img')  
    // 获取可视区域的高度  
    const viewHeight = window.innerHeight || document.documentElement.clientHeight  
    // num用于统计当前显示到了哪一张图片,避免每次都从第一张图片开始检查是否露出  
    let num = 0  
    function lazyload(){  
        for(let i=num; i<imgs.length; i++) {  
            // 用可视区域高度减去元素顶部距离可视区域顶部的高度  
            let distance = viewHeight - imgs[i].getBoundingClientRect().top  
            
            // 如果可视区域高度大于等于元素顶部距离可视区域顶部的高度,说明元素露出  
            if(distance >= 0 ){  
                // 给元素写入真实的src,展示图片  
                imgs[i].src = imgs[i].getAttribute('data-src')  
                // 前i张图片已经加载完毕,下次从第i+1张开始检查是否露出  
                num = i + 1  
            }  
        }  
    }  
    // 监听Scroll事件  
    window.addEventListener('scroll', lazyload, false);  
</script>
相关推荐
康小汪2 小时前
AI 写 Vue 总写成同一个味道:给它装 Skills,装的不是知识是边界
前端·vue.js·人工智能·ai编程·最佳实践
智能运维指南3 小时前
研制过程“两张皮“怎么破:研制一体化支撑平台的定位、能力边界与落地前提
java·前端·人工智能·嘉为蓝鲸
蒸鱼Yuzheng4 小时前
移动端 Overdraw 治理:从单帧热图到屏幕空间预算
性能优化·gpu·renderdoc·overdraw·移动端渲染
白山编程大哥4 小时前
Java 后端如何优雅地把 List 集合返回给前端
java·前端·list
Flynt5 小时前
我把热榜那篇"禁用 axios"逐条实测了一遍:结论大体对,坑在它没讲的地方
前端·javascript·axios
Csvn6 小时前
bundle优化
前端
北冥有鱼6 小时前
发版后动态路由点击报 `Failed to fetch dynamically imported module`」问题上的完整排查与修复过程
前端·vue.js
静默回滚6 小时前
视频压到 25 MB 以内,码率要算、音轨要扣、余量要留
前端
用户37203749260186 小时前
把 10MB 中文语义模型塞进浏览器:STSB 做到教师模型的 93%,但线上 top1 只有 42%
前端
魏慕安6 小时前
渲染提速 6 倍:搭建引擎的门控优化实录
性能优化