Javascript Position Attributes

引言

在日常的工作中,很多场景下需要知道一个元素的位置信息与尺寸信息,但是涉及到这方面的属性与方法很多,有时候难以抉择使用哪个方法或属性比较合适,这就需要我们详尽掌握元素位置与尺寸相关的知识,才能熟能生巧,灵活运用。

元素的尺寸

clientHeight&clientWidth

这两个属性都是整数形式的只读的属性,其中:

1
2
clientHeight = CSS height + CSS padding - height of horizontal scrollbar
clientWidth = CSS width + CSS padding

如下图所示:
MDN clientHeight and clientWidth schematic diagram

offsetHeight&offsetWidth

这两个属性也是整数形式的只读的属性,其中:

1
2
offsetHeight = CSS height(include horizontal scrollbar if rendered) + CSS padding + CSS borders (可以理解为元素包括边框的高度)
offsetWidth = CSS width(include vertical scrollbar if rendered) + CSS padding + CSS borders(可以理解为元素包括边框的宽度)

如下图所示:
MDN offsetHeight and offsetWidth schematic diagram

scrollHeight&scrollWidth

同样的,这两个属性也是整数形式的只读的属性,在元素没有出现滚动条的情况下,scrollHeight 与 clientHeight 相等,scrollWidth 与 clientWidth 相等,所以大部分情况下涉及到这两个值是在元素中出现滚动的情况。其中:
scrollHeight 代表竖向滚动中包括可见与不可见部分的元素的高度,包括 height 和 padding,也包括了其伪元素的高度,如下图所示:
MDN scrollHeight schematic diagram
有了对 scrollHeight 的理解,对应的 scrollWidth 也相应的好理解了,该属性代表的是横向滚动中包括可见与不可见部分的元素的宽度,包括 width 和 padding,也包括了其伪元素的宽度

元素的位置

  1. clientTop&clientLeft
    这两个属性都是整数形式的只读的属性,返回的是元素的内边距的外边缘(clientWidth 与 clientHeight 对应区域的边缘)和对应边框的外边缘的水平距离与垂直距离,通常情况下,clientTop 指的是上边框的高度,clientHeight 指的是左边框的高度。极端情况下爱,在有滚动条且滚动条位置在左侧或者顶部的时候,clientLeft 和 clientTop 的返回值包含这些对应滚动条的宽高。

  2. offsetTop&offsetLeft
    这两个属性都是整数形式的只读的属性,返回的是相对于 offsetParent 或文档的 top 与 left 值,其中相对于祖先元素是已定位的元素或者一些其他元素(td, th, table),这些属性返回的值是相对于这些元素的 top 与 left,其他的返回值则相对于文档的定位进行相应的值返回。

  3. scrollTop&scrollLeft
    这两个属性则float形式的可读写属性,返回的值是元素对应水平方向和垂直方向的滚动的距离,通过设置它们的值可以让对应的元素内容滚动。当元素没有滚动条时,这两个属性的值恒为 0.

Element.getBoundingClientRect()

getBoundingClientRect()这个方法返回元素的尺寸以及相对于视口(viewport)的位置信息,返回的值包括 width,height,left,top,right,bottom,x,y 这些只读信息。其中:
left,right,top,bottom 这四个值都是元素相对于视口的原点的位置
heigth,width 则是元素的整体尺寸。包含了滚动隐藏部分的尺寸,也包括了元素的 padding 与 border。

实际应用

有了对以上属性以及方法的理解与掌握,我们可以实现图片懒加载的效果。

懒加载的意义

页面中占用带宽资源最多的往往是图片,在一些电商类网站上,当页面加载图片资源过多时,往往会造成页面的加载缓慢,这会削弱用户的体验,同时增加客户端与服务器不必要的带宽。使用了懒加载则可以优化页面的性能,增加用户体验。

实现原理

1.首先实现一个最简单的懒加载:

1
2
3
<img class="lazy-load" src="" data-src="example.png" />; //element
const image = document.querySelect('.lasy-load');
image.setAttribute(image.getAttribute('data-src'));

当浏览器遇到 img 标签且 img 标签的 src 有值时,就会发起请求获取图片。因此我们先赋值 src 为空字符串,在需要的时候再进行相应的赋值,就可以做到最简单的懒加载。那么什么时候是比较合适的时候呢? 2.如何判断元素是否在可视区域内?

第一种方式:

1
2
3
4
const A = window.innerHeigh || document.documentElement.clientHeight //可视窗口的高度
const B = imageElement.offsetTop //相对于文档顶部的定位
const C = document.documentElement.scrollTop //滚动条滚动的距离
A > B - C 则说明元素在可视区域内

第二种方式:

1
2
3
const A = window.innerHeight || document.documemtElement.clientHeight //可视窗口的高度
const B = imageElement.getBoundingClientRect().top
A > B 则说明元素在可视区域内

知道了对应的检测元素是否在可视区域内的原理,如何实现懒加载就呼之欲出了。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<style>
img {
display: block;
width: 500px;
height: 500px;
margin-bottom: 100px;
}
</style>

<body>
<img src="/image/default.jpg" data-src="/image/01.png" alt="" />
<img src="/image/default.jpg" data-src="/image/02.png" alt="" />
<img src="/image/default.jpg" data-src="/image/03.png" alt="" />
<img src="/image/default.jpg" data-src="/image/04.png" alt="" />
<img src="/image/default.jpg" data-src="/image/05.png" alt="" />
<img src="/image/default.jpg" data-src="/image/06.png" alt="" />
<img src="/image/default.jpg" data-src="/image/07.png" alt="" />
<img src="/image/default.jpg" data-src="/image/08.png" alt="" />
<img src="/image/default.jpg" data-src="/image/09.png" alt="" />
<img src="/image/default.jpg" data-src="/image/10.png" alt="" />
</body>
<script>
const viewHeight =
window.innerHeight || document.documentElement.clientHeight;
const images = document.querySelectorAll('img');
function lazyload() {
Array.prototype.forEach.call(images, img => {
const dataSrc = img.getAttribute('data-src');
if (!dataSrc) return;
const rect = img.getBoundingClientRect();
if (rect.top < viewHeight) {
img.setAttribute('src', dataSrc);
}
});
lazyload();
document.addEventListener('scroll', lazyload);
}
</script>
</html>

参考资料

Understanding offsetWidth, clientWidth, scrollWidth and -Height, respectively
MDN-Element: methods and properties

Comments