个性签名: 生如夏花,逝如冬雪;人生如此,何悔何怨。

前言: 经常需要计算元素的大小或者所在页面的位置,offsetWidth,clientWidth,scrollWidth,scrollTop这几个关键字的出现更是家常便饭,每次碰到都需要事先实验一番。为了下次开发提高效率。在这里一次性做个总结,以用来判断元素是否在可视区域以及用原生js简单实现懒加载。文末有个简单的懒加载实现的demo,有需要的可以看一下。

目录

工欲善其事,必先利其器。在判断元素是否在可视区域实现简单的原生懒加载前,我们先简单回顾下以下几个关键的概念。

ps: 如果你对这些概念已经比较熟悉了,可以直接跳到第五点查看关键代码示例。

1. 偏移量

偏移量(offset dimension),元素的可见大小由其高度、宽度决定,包括所有内边距、滚动条和边框大小(注意,不包括外边距)。通过下列4个属性可以取得元素的偏移量。

偏移量

概念

公式

offsetHeight

元素在垂直方向上占用的空间大小,以像素计。包括元素的高度、(可见的) 水平滚动条的高度、上边框高度和下边框高度。

offsetHeght = content + padding + border + scrollX

offsetWidth

元素在水平方向上占用的空间大小,以像素计。包括元素的宽度、(可见的)垂 直滚动条的宽度、左边框宽度和右边框宽度。

offsetWidth = content + padding + border + scrollY

offsetLeft

元素的左外边框至**包含元素的左内边框之间的像素距离。

offsetTop

元素的上外边框至包含元素的上内边框之间的像素距离。

其中,offsetLeft 和 offsetTop 属性与包含元素有关,包含元素的引用保存在 offsetParent 属性中。**offsetParent 属性不一定与 parentNode 的值相等。

如下图显示

注意: 所有这些偏移量属性都是只读的,而且每次访问它们都需要重新计算。因此,应该尽量避免重复访问这些属性;如果需要重复使用其中某些属性的值,可以将它们保 存在局部变量中,以提高性能。

这也是上篇文章文字跑马灯项目中(戳此跳转),为什么增加padding后,textWidth需要重新获取的原因

小结

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

2. 客户区大小

客户区大小是只读的,每次访问都要重新计算的。

客户区大小

概念

公式

clientWidth

clientWidth 属性是元素内容区宽度加 上左右内边距宽度;

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 兼容性比较

在兼容性方面,我们知道越原始的方法兼容性是最好的,那么第二种方法和第三种方法能否代替第三种方法呢?我们来看看。

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

所以,如果在移动端和桌面端都要做兼容适配的话,方法二完全可以代替方法一进行适配了。如果仅仅是桌面端适配(比如运营后台),我们或许可以尝试下新的IntersectionObserver方法,毕竟IntersectionObserver里面还有更多丰富的功能等着我们去体验呢。

5.5 实例

有时,我们希望某些静态资源(比如图片),只有用户向下滚动,它们进入视口时才加载,这样可以节省带宽,提高网页性能。这就叫做"惰性加载",也称为懒加载。

惰性加载预览DEMO(放入你的本地图片即可通过更换不同方法实现懒加载)

------------------------------ 华丽的分割线 ---------------------------

ps: 有公众号大佬想减轻日常写推文的时间消耗,收购技术原创文章的稿子放在自己公众号展示推送的,可以联系找我合作哈。(在公众号里可以查到我的联系方式)

关于我

参考

android camera viewport rect,如何判断元素是否在可视区域ViewPort相关推荐

  1. android自定义camera预览区域,android camera摄像surfaceview预览界面特定区域(该区域可移动)...

    1.自定义一个imageview用来设定surfaceview上的特定区域. public class DrawImageView extends ImageView { private Paint ...

  2. 如何获取元素与当前可视区域顶部的距离

    转载自这个老哥 https://www.cnblogs.com/lufy/p/6704945.html?utm_source=itdadao&utm_medium=referral getBo ...

  3. android 预览和拍照成像方向不一致,android 拍照 预览图与 照片分辨率(可视区域)不一致...

    问题来源是来自项目自定义相机模块,问题出现在拍摄下的照片与预览的照片课时范围不一致,在测试手机上出现的具体情况是拍摄的照片可视宽度大于预览的画面. 问题出在 该自定义相机采用了全屏预览画面,以及虚拟按 ...

  4. [转] getBoundingClientRect判断元素是否可见

    getBoundingClientRect介绍 getBoundingClientRect获取元素位置 getBoundingClientRect用于获得页面中某个元素的左,上,右和下分别相对浏览器视 ...

  5. php开发是可视的吗,javascript,html_Jquery判断页面元素是否在浏览器的可视区域内,javascript,html,css,html5 - phpStudy...

    Jquery判断页面元素是否在浏览器的可视区域内 前端开发中,有时需要判断某个元素是否在浏览器的可视区域内,或者是否已经滚动出了可视区域.首先想到的便是javascript操作,原生方法自然可以,不过 ...

  6. 【web】仿微博浏览量自增(判断元素是否在可视区+停留2s事件响应)

    浏览量自增 需求分析 微博.空间动态中经常能看到浏览量统计,不同于博客,点击之后浏览量自动加1,这种碎片化的推送信息,浏览次数不能以常规的点击方式来统计,用户可能甚至根本不会点击内容,匆匆一瞥就把滚动 ...

  7. 控制元素到达可视区域内触发动效

    控制元素到达可视区域内触发动效,代码参考了别人的,有修改,时间久了,出处想不起来.后面遇到了会补充源码地址.<!DOCTYPE html> <html> <head> ...

  8. js如何监听元素事件是否被移除_JavaScript 监听元素是否进入/移出可视区域

    JavaScript 监听元素是否进入/移出可视区域 常规操作 防抖节流 IntersectionObserver 兼容的代码 常规操作 通常的做法是,监听srcoll事件,根据元素的offset来判 ...

  9. android camera viewport rect,Unity 实现屏幕抖动效果(通过Camera Viewport Rect)

    实现屏幕抖动其实是实现相机Camera的抖动,通过修改Viewport Rect属性改变屏幕位置 以下是百度到的代码: public class ShakeCamera : MonoBehaviour ...

最新文章

  1. VMWare常用快捷键
  2. HP LoadRunner 12.02 Tutorial T7177-88037教程独家中文版
  3. Java虚拟机:JVM 主要组成部分与内存区域
  4. C++ STL 容器 string
  5. Oracle笔记:备份还原
  6. 猎豹浏览器缓存文件在哪 猎豹浏览器缓存文件位置说明
  7. chrome浏览器无法加载百度网页启动组件怎么办
  8. 英语四六级听力考试选项技巧
  9. 聚簇索引和非聚簇索引详解
  10. 用 Python 制作关不掉的端午安康弹窗
  11. 网友评荣耀V30:同价位无对手 除了双模5G和价格还有哪些原因
  12. BZOJ4033 [HAOI2015]树上染色 【树形dp】
  13. EOS开发DApp 创建EOS钱包和账号
  14. 系统分析与设计方法---需求分析与软件设计
  15. 【图像去噪】基于马尔可夫随机场实现图像去噪附matlab代码
  16. WPF高性能绘图之DrawingCanvas、DrawingVisual、Button的同时使用
  17. python发outlook邮件_python对outlook邮件整理
  18. c3 linearization详解
  19. Java Cache 入门
  20. 元宇宙的驱动力是什么?

热门文章

  1. unity动态生成render texture
  2. 2021 年全国职业院校技能大赛 网络搭建与应用赛项
  3. 行销e破解_Google如何让广告行销人员像我一样追踪您的孩子
  4. 网狐棋牌 二次开发流程
  5. 悄悄说--一个Swing界面的仿qq聊天软件
  6. ZK框架的分析与应用
  7. python 完整的海龟策略_9海龟策略_python量化交易_Python视频-51CTO学院
  8. python与算法社区_3社区分类算法_python量化交易_Python视频-51CTO学院
  9. 无人酒店开业、无人车上路,不被时代抛弃,看懂这2点
  10. 移动端浏览器沉浸式导航