怎样推断元素是不是在可视地区ViewPort

特性署名: 生如夏花,逝如冬雪;人生云云,何悔何怨。

媒介: 常常须要盘算元素的大小也许地点页面的位置,offsetWidth,clientWidth,scrollWidth,scrollTop这几个症结字的涌现更是粗茶淡饭,每次遇到都须要事前试验一番。为了下次开辟进步效力。在这里一次性做个总结,
以用来推断元素是不是在可视地区以及用原生js简朴完成懒加载。文末有个简朴的懒加载完成的demo,有须要的能够看一下。

目次

《怎样推断元素是不是在可视地区ViewPort》

工欲善其事,必先利其器。在推断元素是不是在可视地区完成简朴的原生懒加载前,我们先简朴回忆下以下几个症结的观点。

ps: 假如你对这些观点已比较熟习了,能够直接跳到第五点检察症结代码示例。

1. 偏移量

偏移量(offset dimension),元素的可见大小由其高度、宽度决议,包括一切内边距、转动条和边框大小(注重,不包括外边距)。经由过程以下4个属机能够获得元素的偏移量。

偏移量观点公式
offsetHeight元素在垂直方向上占用的空间大小,以像素计。包括元素的高度、(可见的) 程度转动条的高度、上边框高度和下边框高度。offsetHeght = content + padding + border + scrollX
offsetWidth元素在程度方向上占用的空间大小,以像素计。包括元素的宽度、(可见的)垂 直转动条的宽度、左边框宽度和右边框宽度。offsetWidth = content + padding + border + scrollY
offsetLeft元素的左外边框至**包括元素的左内边框之间的像素间隔。
offsetTop元素的上外边框至包括元素的上内边框之间的像素间隔。

个中,offsetLeft 和 offsetTop 属性与包括元素有关,包括元素的援用保存在 offsetParent 属性中。**offsetParent 属性不一定与 parentNode 的值相称。

以下图显现
《怎样推断元素是不是在可视地区ViewPort》

注重: 一切这些偏移量属性都是只读的,而且每次接见它们都须要从新盘算。因而,应当只管防止反复接见这些属性;假如须要反复运用个中某些属性的值,能够将它们保 存在局部变量中,以进步机能。

这也是上篇文章笔墨跑马灯项目中(戳此跳转),为何增添padding后,textWidth须要从新猎取的缘由
《怎样推断元素是不是在可视地区ViewPort》

小结

偏移量: 只读属性;包括转动条和边框,不包括外边距。

2. 客户区大小

客户区大小是只读的,每次接见都要从新盘算的。

客户区大小观点公式
clientWidthclientWidth 属性是元素内容区宽度加 上摆布内边距宽度;clientWidth = content + padding
clientHeight元素内容区高度加上高低内边距高度clientHeight = content + padding

最常用到这些属性的状况,就是肯定浏览器视口大小的时刻(在 IE7 之前的版本中)。以下面的例子所示:

function getViewport(){
    // 搜检 document.compatMode 属性,以肯定浏览器是不是运转在混淆形式。
    // Safari3.1 之前的版本不支持这个属性,因而就会自动实行 else 语句
    if (document.compatMode == "BackCompat"){
        return {
            width: document.body.clientWidth,
            height: document.body.clientHeight
        };
    } else {
        return {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight
        }; 
    }
}

小结

客户区大小: 只读属性;不包括转动条和边框,不包括外边距。

3. 转动大小

观点
scrollHeight在没有转动条的状况下,元素内容的总高度。
scrollWidth在没有转动条的状况下,元素内容的总宽度。
scrollLeft被隐蔽在内容地区左边的像素数。经由过程设置这个属机能够转变元素的转动位置。
scrollTop被隐蔽在内容地区上方的像素数。经由过程设置这个属机能够转变元素的转动位置。

scrollWidth 和 scrollHeight 重要用于肯定元素内容的现实大小。

scrollLeft 和 scrollTop属性既能够肯定元素当前转动的状况,也能够设置元素的转动位 置。在元素尚未被转动时,这两个属性的值都即是 0。假如元素被垂直转动了,那末 scrollTop 的值 会大于 0,且示意元素上方不可见内容的像素高度。假如元素被程度转动了,那末 scrollLeft 的值会 大于 0,且示意元素左边不可见内容的像素宽度。这两个属性都是能够设置的,因而将元素的 scrollLeft 和 scrollTop 设置为 0,就能够重置元素的转动位置。比方:上篇文章笔墨跑马灯项目中scrollLeft的运用(戳此跳转)

小结

只读属性,不包括转动条、border。

4. 肯定元素大小

getBoundingClientRect

getBoundingClientRect的兼容性写法:

关于不支持 getBoundingClientRect()的浏览器,能够经由过程其他手腕获得雷同的信息。平常来 说,right 和 left 的差值与 offsetWidth 的值相称,而 bottom 和 top 的差值与 offsetHeight 相称。综合上述,就能够建立出下面这个跨浏览器的函数:


function getElementLeft(element){
    var actualLeft = element.offsetLeft;
    var current = element.offsetParent;
    while (current !== null){
        actualLeft += current.offsetLeft;
        current = current.offsetParent;
    }
    return actualLeft;
}

function getElementTop(element){
    var actualTop = element.offsetTop;
    var current = element.offsetParent;
    while (current !== null){
        actualTop += current. offsetTop;
        current = current.offsetParent;
    }
    return actualTop;
}

function getBoundingClientRect(element) {
    var scrollTop = document.documentElement.scrollTop;
    var scrollLeft = document.documentElement.scrollLeft;
    if (element.getBoundingClientRect) {
        if (typeof arguments.callee.offset != "number") {
            var temp = document.createElement("div");
            temp.style.cssText = "position:absolute;left:0;top:0;"; document.body.appendChild(temp);
            arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop; document.body.removeChild(temp);
            temp = null;
        }
        var rect = element.getBoundingClientRect();
        var offset = arguments.callee.offset;
        return {
            left: rect.left + offset,
            right: rect.right + offset,
            top: rect.top + offset,
            bottom: rect.bottom + offset
        };
    } else {
        var actualLeft = getElementLeft(element);
        var actualTop = getElementTop(element);
        return {
            left: actualLeft - scrollLeft,
            right: actualLeft + element.offsetWidth - scrollLeft,
            top: actualTop - scrollTop,
            bottom: actualTop + element.offsetHeight - scrollTop
        }
    }
}

5.推断元素是不是在可视地区

晓得了元素的大小以及所位于的地区外,我们能够做些什么呢?我们能够经由过程上面学到的学问点来检测元素是不是在可视地区,再说大一点,这也是懒加载图片的完成道理。

5.1 第一种要领

公式: el.offsetTop – document.documentElement.scrollTop <= viewPortHeight

function isInViewPortOfOne (el) {
    // viewPortHeight 兼容一切浏览器写法
    const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight 
    const offsetTop = el.offsetTop
    const scrollTop = document.documentElement.scrollTop
    const top = offsetTop - scrollTop
    console.log('top', top)
     // 这里有个+100是为了提早加载+ 100
    return top <= viewPortHeight + 100
}

5.2 第二种要领

公式: el.getBoundingClientReact().top <= viewPortHeight

实在, el.offsetTop – document.documentElement.scrollTop = el.getBoundingClientRect().top, 应用这点,我们能够用下面代码替代要领一

function isInViewPortOfTwo (el) {
    const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight 
    const top = el.getBoundingClientRect() && el.getBoundingClientRect().top
    console.log('top', top)
    return top  <= viewPortHeight + 100
}

5.3 第三种要领

公式: intersectionRatio > 0 && intersectionRatio <= 1

// 定义一个交织视察器
const io = new IntersectionObserver(ioes => {
    ioes.forEach(ioe => {
        const el = ioe.target
        const intersectionRatio = ioe.intersectionRatio
        if (intersectionRatio > 0 && intersectionRatio <= 1) {
            loadImg(el)
            io.unobserve(el)
        }
         el.onload = el.onerror = () => io.unobserve(el)
    })
})
// 实行交织视察器
function isInViewPortOfThree (el) {
    io.observe(el)
}

5.4 兼容性比较

在兼容性方面,我们晓得越原始的要领兼容性是最好的,那末第二种要领和第三种要领可否替代第三种要领呢?我们来看看。

《怎样推断元素是不是在可视地区ViewPort》

《怎样推断元素是不是在可视地区ViewPort》

从caniuse的数据来看,getBoundingClientReact的适配状况很乐观了。

所以,假如在挪动端和桌面端都要做兼容适配的话,要领二完全能够替代要领一举行适配了。假如仅仅是桌面端适配(比方运营背景),我们也许能够尝试下新的IntersectionObserver要领,毕竟IntersectionObserver内里另有更多雄厚的功用等着我们去体验呢。

5.5 实例

偶然,我们愿望某些静态资本(比方图片),只要用户向下转动,它们进入视口时才加载,如许能够节约带宽,进步网页机能。这就叫做”惰性加载”,也称为懒加载。

惰性加载预览DEMO(放入你的当地图片即可经由过程替换差别要领完成懒加载)

—————————— 华美的分割线 —————————

ps: 有民众号大佬想减轻一样平常写推文的时候斲丧,收买手艺原创文章的稿子放在本身民众号展现推送的,能够联络找我协作哈。(在民众号里能够查到我的联络方式)

关于我

《怎样推断元素是不是在可视地区ViewPort》

参考

    原文作者:张高
    原文地址: https://segmentfault.com/a/1190000017150136
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞