在 Javascript 的开发过程中,我们总会看到类似如下的边界条件判断 (懒加载):
const scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
if(scrollTop + window.innerHeight >= scrollHeight + 50) {console.log('滚动到底了!')
}
这些获取滚动状态的属性,可能我们咋一看能够理解,不过时间久了立马又忘记了。这是因为这些获取各种宽高的属性 api 及其的多,而且几乎都存在兼容性写法。一方面很难记,更重要的是不好理解。下面通过选取常用的几个来讲述下具体 api 的区别, 没有在下面的基本很少会用到,也不必深究。
## 一 挂在 window 上的
window 上最常用的只有 window.innerWidth/window.innerHeight、window.pageXOffset/window.pageYOffset.
其中,window.innerWidth/windw.innerHeight 永远都是窗口的大小,跟随窗口变化而变化。window.pageXOffset/window.pageYOffset 是 IE9+ 浏览器获取滚动距离的,实质跟 document.documentElement/document.body 上的 scrollTop/scrollLeft 功能一致,所以日常都使用兼容写法:
const scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
二 挂在 document 上的
1 clientWidth/clientHeight: 元素内部的宽高.
记住公式:
clientWidth/clientHeight = padding + content 宽高 - scrollbar 宽高 (如有滚动条)
2 offsetWidth/offsetHeight
个人觉得这个名字有点误导人,压根没有偏移的意思,记住公式即可:
offsetWidth/offsetHeight = clientWidth/clientHeight(padding + content) + border + scrollbar
由上述公式,可以得到第一个示例,即 ” 获取滚动条的宽度 (scrollbar)”:
const el = document.querySelect('.box')
const style = getComputedStyle(el, flase)// 获取样式
const clientWidth = el.clientWidth, offsetWidth = el.offsetWidth
//parseFloat('10px', 10) => 10
const borderWidth = parseFloat(style.borderLeftWidth, 10) + parseFloat(style.borderRightWidth, 10)
const scrollbarW = offsetWidth - clientWidth - borderWidth
3 offsetTop/offsetLeft
这两个才是真的意如其名,指的是元素上侧或者左侧偏移它的 offsetParent 的距离。这个 offsetParent 是距该元素最近的 position 不为 static 的祖先元素,如果没有则指向 body 元素。说白了就是:” 元素 div 往外找到最近的 position 不为 static 的元素,然后该 div 的边界到它的距离 ”。
由此,可以得到第二个示例,即 ” 获得任一元素在页面中的位置 ”:
const getPosition = (el) => {
let left = 0, top = 0;
while(el.offsetParent) {
// 获取偏移父元素的样式, 在计算偏移的时候需要加上它的 border
const pStyle = getComputedStyle(el.offsetParent, false);
left += el.offsetLeft + parseFloat(pStyle.borderLeftWidth, 10);
top += el.offsetTop + parseFloat(pStyle.borderTopWidth, 10);
el = el.offsetParent;
}
return {left, top}
}
综上,结合 getBoundingClientRect() 得到综合示例 ” 元素是否在可视区域 ”:
function isElemInViewport(el) {const rt = el.getBoundingClientRect();
return (
rt.top >=0 &&
rt.left >= 0 &&
rt.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rt.right <= (window.innerWidth || document.documentElement.clientWidth)
)
}
其中,getBoundingClientRect 用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置:
本文收录在个人的 Github 上 https://github.com/kekobin/blog/issues/1, 觉得有帮助的,欢迎 start 哈!