2023-03-08
前端
00

目录

1. 滚动距离计算
2. getBoundingClientReat方法计算
3. IntersectionObserver监听
4.<img> 标签属性loading
最后

1. 滚动距离计算

offsetTop,scrollTop,clientHeight原生API获取距离像素计算

offsetTop:获取当前元素与其父级元素顶部内边距的距离

scrollTop:当前元素滚动超出的高度

clientHeight:当前元素的可视高度

"灵魂画手"绘图

img元素offsetTop - 父级元素scrollTop<父级元素clientHeight,即说明img已滚动进入父可视区域

css
#view { width: 300px; height: 500px; margin: 30px auto; overflow-y: auto; } .parent { height: 1000px; } img { margin-top: 800px; }
html
<div id="view"> <div class="parent"> <img alt="..." loading="lazy" class="img" data-src="https://tse1-mm.cn.bing.net/th?id=OIP-C.FaG6dzohGs3q45-DwsEyQQHaEK&w=165&h=100&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2"> </div> </div>
js
let view = document.getElementById('view'); let img = document.getElementsByClassName('img')[0]; view.onscroll = function () { let sh = this.clientHeight; let st = this.scrollTop; let ch = img.offsetTop; ch - st < sh && (img.src = img.dataset.src) }

用户频繁滚动鼠标时,会多次触发onscroll事件计算滚动距离,消耗性能又没有意义,所以需要控制函数执行的次数,减少性能的消耗,对滚动事件进行防抖处理

开发中为减少反复写防抖函数,已经将它封装入@lihai-js/tool, 开箱即用

@lihai-js/tool地址https://github.com/lihai-boop/tool

js
let img = document.getElementsByClassName('img')[0]; let view = document.getElementById('view'); function debounce (fn, wait = 1000, immediate = false) { const self = this immediate && fn.call(this) return function () { self.debounceTime && clearTimeout(self.debounceTime) self.debounceTime = setTimeout(() => { fn.apply(this, arguments) }, wait) } } view.onscroll =debounce(function () { let sh = view.clientHeight; let st = view.scrollTop; let ch = img.offsetTop; ch - st < sh && (img.src = img.dataset.src) })

2. getBoundingClientReat方法计算

Element.getBoundingClientReat()方法返回元素的大小及其相对于视口的位置。

该方法返回一个DOMRect对象,对象包括left, top, right, bottom, x, y, width, 和 height这8个属性值。除了widthheight 以外的属性是相对于视图窗口的左上角来计算的。

Element.getBoundingClientRect() - Web API 接口参考 | MDN (mozilla.org)

滚动计算距离列举的代码例子来说,可视窗口为浏览器窗口,对imgdom对象使用getBoundingClientReat()获取top,top即为浏览器窗口左上角到img标签左上角的像素距离点

利用上述点,当top值小于浏览器窗口高度时,说明img已滚动于可视区域,即进行加载

css
#view { width: 300px; height: 500px; margin: 30px auto; overflow-y: auto; } .parent { height: 1000px; } img { margin-top: 800px; margin-bottom: 30px; }
html
<div id="view"> <img alt="..." class="img" data-src="https://p.pstatp.com/origin/pgc-image/c206105e0c46482a85b69a67a59ce682" /> </div>
js
let img = document.getElementsByClassName('img')[0]; let view = document.getElementById('view'); //省略防抖代码 window.onscroll = debounce(() => { let clientHeigth = view.clientHeight; let { top } = img.getBoundingClientRect(); top < clientHeigth && (img.src = img.dataset.src); }) view.onscroll =debounce(function () { let sh = view.clientHeight; let { top } = img.getBoundingClientRect(); top<sh && (img.src = img.dataset.src) })

3. IntersectionObserver监听

IntersectionObserverAPI原理与2. getBoundingClientReat方法计算一样,官方认为图片懒加载,开发者既要获取top值,又要监听滚动事件,还要进行防抖处理,一系列操作麻烦不方便。为了简化它,官方提供了IntersectionObserver接口。

IntersectionObserver(callback[, options])

当监听的元素达到要求后,触发callback回调函数,它接收两个参数

IntersectionObserver API 使用教程 - 阮一峰的网络日志 (ruanyifeng.com)

js
let img = document.getElementsByClassName('img')[0]; let view = document.getElementById(view); let ob = new IntersectionObserver(function (changes) { changes.forEach(val => { let { isIntersecting, target } = val; isIntersecting && (target.src = target.dataset.src); }) }, { root: view, threshold: [0] }) ob.observe(img);

4.<img> 标签属性loading

兼容性差,不推荐

<img>标签属性loding,可选值:

eager:立即加载图像

lazy:延迟加载图像,直到它和视口接近到一个计算得到的距离,由浏览器定义

详细介绍:https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/img#attr-loading

html
<div class="parent"> <img loading="lazy" src="https://tse1-mm.cn.bing.net/th?id=OIP-C.FaG6dzohGs3q45-DwsEyQQHaEK&w=165&h=100&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2" alt="..."> </div>

最后

期待各位同学指点补充!

觉得文章有用的同学点赞一波!

本文作者:凌览

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!