先放上一张经典图
看不懂,没关系!接下来耐心看完必然有不一样的收获。
我们常遇到的是实际是这么几个属性:
如果不把它们弄清楚就会导致每次遇到时都混淆不清,下面就逐一看看这么些属性。
(1)offsetTop
HTMLElement.offsetTop为只读属性,它返回当前元素相对于其 offsetParent 元素的顶部内边距的距离。--MDN
【巧记】offset本身就是偏移的意思,所以但凡遇到 offsetXxx 属性时需要先考虑的是参考对象。而offsetTop会经常性的被误认为其参考对象就是父元素,并不是的!!!
HTMLElement.offsetParent
是一个只读属性,返回一个指向最近的(指包含层级上的最近)包含该元素的定位元素或者最近的table,
td,
th,
body
元素。当元素的style.display
设置为 "none" 时,offsetParent
返回null
。offsetParent
很有用,因为offsetTop
和offsetLeft
都是相对于其内边距边界的。--MDN
关于offsetParent的理解,这位作者给出的解读,我个人比较赞同的。
(参考的对象是)祖先(不一定是父元素,一直往上找)元素、离自己最近、position不为static(static是position的默认值,如果一个元素不设置position,默认是static定位,因此offsetTop所参考的对象的position必须是relative,absolute,fixed中的一个)--原文链接
So实在记不住,就在每次使用offsetTop的时候看看element.offsetParent,那就可以知道这个offsetTop的参考对象究竟是谁。只有明确参考对象是谁,业务中使用offsetTop,才不会用错。 同理,offsetLeft、offsetRight、offsetBottom也是如此。
另外两个offset属性:offsetHeight和offsetWidth。
HTMLElement.offsetHeight 是一个只读属性,它返回该元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数。 通常,元素的offsetHeight是一种元素CSS高度的衡量标准,包括元素的边框、内边距和元素的水平滚动条(如果存在且渲染的话),不包含:before或:after等伪类元素的高度。 --MDN
这里需要知道的就是offsetHeight和clientHeight的小区别,先留下个疑问一?
(2)clientHeight
这个属性是只读属性,对于没有定义CSS或者内联布局盒子的元素为0,否则,它是元素内部的高度(单位像素),包含内边距,但不包括水平滚动条、边框和外边距。--MDN
MDN文档的配图就很直接的解释了clientHeight和clientWidth.
client这类属性的记忆点就在于:client,它只与元素本身相关,不关注元素外的东西。
结合上面我们说的疑问一,作个解答。 但凡遇到 offsetXxx 属性时需要先考虑的是参考对象。 这里的offsetHeight参考的就是client。而client是只与元素本身相关,所以clientHeight就不包括水平滚动条、边框和外边距。相比较,offsetHeight则会把它们都包括了,除去外边距margin
HTMLElement.offsetHeight 是一个只读属性,它返回该元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数。 通常,元素的offsetHeight是一种元素CSS高度的衡量标准,包括元素的边框、内边距和元素的水平滚动条(如果存在且渲染的话),不包含:before或:after等伪类元素的高度。--MDN
紧接着我们继续理解下clientTop这种属性,MDN的定义是一个元素顶部边框的宽度(以像素表示)。不包括顶部外边距或内边距。clientTop 是只读的。
心生疑问二:那不就是盒子的border大小?clientTop===border?
答:可以这么理解的,但和border之间会存在小差异。详细解答
https://blog.csdn.net/GuoXiaoHong7758521/article/details/90317759
总结差异点就是:clientTop是个整数值,不带单位。
同理:clientLeft、clientRight、clientBottom
(3)scrollTop和scrollHeight
看了前面两个就知道我这里想说什么了,scroll那必然就是和滚动条有关系的了。
scrollTop
Element.scrollTop 属性可以获取或设置一个元素的内容垂直滚动的像素数。这个属性可读可写,简要理解就是滚动条滚动的距离 --MDN
所以,我们是可以通过scrollTop来控制滚动条的滚动的
scrollHeight
Element.scrollHeight 这个只读属性是一个元素内容高度的度量,包括由于溢出导致的视图中不可见内容。--MDN
这时候就需要知道scrollHeight和clientHeight的区别了。自个回顾下clientHeight的定义。
scrollHeight代表包括当前不可见部分的元素的高度,可以理解为是个总共高度。而可见部分的高度其实就是clientHeight,也就是scrollHeight>=clientHeight恒成立。在有滚动条时讨论scrollHeight才有意义,当没有滚动条时scrollHeight==clientHeight恒成立
同理,scrollLeft和scrollWidth如此类推。
到此,我们就解读完了经典图里的大部分标注了,剩下的style类属性,就是css里设置的样式了,不作解读。
读完上述属性,我们需要从两个角度来看看这些属性的应用方向。
前置条件:子div的高度大于父div,即子div会溢出,且溢出会滚动,那么父div就相当于可视区域了。
这时候,讨论的是这么几个值scrollHeight、clientHeight、scrollTop
就会存在这么几个情况
(1)scrollTop=0,没有滚动
(2)scrollTop>0,有滚动距离,但没有滚动到底部
(3)scrollTop=scrollHeight-clientHeight,滚动到了底部
所以在判断是否已经滚动到底部的时候就可以,用第三种情况来判断。
疑问三:为什么这里用clientHeight不用offsetHeight?
答:根据两者的定义,感觉应该都可以。因为两者相差不大,就是相差了个border的大小和水平滚动条的高度(一般情况下,垂直滚动时就不会设置水平滚动),那如果子div没有border,实际上两个值是一样的。视实际情况斟酌。
常见功能:页面滚动到某个位置
window.scrollTo()方法可以帮我们实现这个功能。问题就在于:某个位置这个值怎么获取?
下面就介绍两个获取html元素与浏览器窗口相关的距离变量
(1)getBoundingClientRect()
Element.getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置。 返回的结果是包含完整元素的最小矩形,并且拥有left, top, right, bottom, x, y, width, 和 height这几个以像素为单位的只读属性用于描述整个边框。
这里就涉及到了可视窗口的概念了,可视窗口就是浏览器看到页面的区域,简称视口。
当我们需要获取页面中任意元素与这个视口的距离时可以用getBoundingClientRect()方法
理解:
这个方法获取到的top值是会随滚动条变化而变化的。
这个方法获取到的方位值(left、top、right、bottom)会存在负值的情况
(2)window.scrollY
定义:返回文档在垂直方向已滚动的像素值
根据业务实际情况来获取某个位置的值
1. 懒加载:下拉列表分页、下拉加载图片
懒加载的思路简而言之是按需加载。这个按需我们怎么来判断呢?
这里的按需指的就是:是否已经滚动到底部了?
若滚动到底部,我们就获取下一页的数据。
判断是否滚动到底部还记得是哪个公式吗?自己回滚上去再看看。
而实际情况中,不一定就是滚动到底部,可以使滚动到底部某个区间就进行获取下一页数据这个操作。
公式:scrollHeight-scrollTop-offsetHeight< y
2. form表单报错信息定位
首个错误信息需要滚动到视口当中,结合window和html理解,就可以知道不难实现。
方法:只要将Element.getBoundingClientRect().top+window.scrollY就可以获取到报错元素在文档的位置了,你说是不是呢?
而且是不管任何时候,这个获取方法都成立。对于元素和视口的关系只有两种情况。
情况一:
元素在可视区域内,这时获取到的Element.getBoundingClientRect().top值为正值,加上window.scrollY恰恰就是元素到文档顶部的距离
情况二:
元素不在可视区域内,这时获取到的Element.getBoundingClientRect().top值为负值,加上window.scrollY,其实就是
scrollY-|Element.getBoundingClientRect().top|
也是元素到文档顶部的距离
所以
window.scrollTo(0,Element.getBoundingClientRect()+window.scrollY)就可以实现将报错元素滚动到视口顶部了
那如果不希望在贴顶部的位置展示,可以再减去一个固定值。