JavaScript判断元素是否在可视区域的三种方法
作者:WebGirl
这这篇文章给大家总结了JavaScript判断元素是否在可视区域的三种方法,getBoundingClientRect,IntersectionObserver和offsetTop、scrollTop这三种方法,文中通过代码示例给大家介绍的非常详细,需要的朋友可以参考下
方法1:getBoundingClientRect
用法
let domRect = dom.getBoundingClientRect();
DOMRect:{ x/left:视图原点(左上角)距离dom左边框距离, y/top:视图原点(左上角)距离dom上边框距离, right:视图原点(左上角)距离dom右边框距离, bottom:视图原点(左上角)距离dom底边框距离, width:dom的宽度,标准盒模型,width = 宽度+padding+border;怪异盒模型,width = 设置的宽度, height:dom的高度, }
所以我们可以根据DOMRect
的中的各个属性来判断dom
是否在可视区域内。
eg:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>getBoundingClientRect可视区域</title> <style> * { margin: 0 } .circle-wrap { position: fixed; top: 50px; right: 50px; padding: 10px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); width: 140px; background: #fff; } .circle-wrap .circle { display: inline-block; width: 20px; height: 20px; border-radius: 50%; background: red; } .card-wrap { height: 2000px; width: 3000px; margin-top: 100px; } .card-wrap .card { width: 200px; height: 200px; padding: 20px; box-sizing: border-box; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); margin-top: 500px; margin-left: 500px; } </style> </head> <body> <div class="circle-wrap"> <span>当下方的卡片在可视区域内,我的圈圈是绿色,否则是红色</span> <span class="circle"></span> </div> <div class="card-wrap"> <div class="card">我是一个卡片</div> </div> <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/lodash.js"></script> <script> const card = document.querySelector(".card"); const circle = document.querySelector(".circle"); const getBoundingClientRectJudge = () => { let domRect = card.getBoundingClientRect(); console.log(domRect) let ch = document.documentElement.clientHeight; let cw = document.documentElement.clientWidth; let isInsert = true; if (domRect.bottom < 0 || domRect.top > ch || domRect.right < 0 || domRect.left > cw) { isInsert = false; } let background = null if (isInsert) { background = "green" } else { background = "red" } circle.style.background = background } window.addEventListener("scroll", _.throttle(getBoundingClientRectJudge, 500)) getBoundingClientRectJudge() </script> </body> </html>
效果图:
问题
getBoundingClientRect
并不能满足所有情况,甚至说,它只能满足一种情况的判断,那就是需要判断的那个dom
节点,它只身处在一个滚动条的情况下。什么意思呢,就是它所有的祖先节点,加起来的滚动条只有1个,如果它父节点有滚动条,父父节点也有滚动条,那这种方法就不好用了,请看示例:
下面展示的结果是错误的,圈圈应该是红色才对。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>getBoundingClientRect可视区域</title> <style> * { margin: 0 } body { height: 2000px; width: 3000px; } .circle-wrap { position: fixed; top: 50px; right: 50px; padding: 10px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); width: 140px; background: #fff; } .circle-wrap .circle { display: inline-block; width: 20px; height: 20px; border-radius: 50%; background: red; } .card-wrap { height: 400px; width: 600px; margin-top: 100px; margin-left: 100px; border: 1px solid green; overflow: auto; } .card-wrap .card { width: 200px; height: 200px; padding: 20px; box-sizing: border-box; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); margin-top: 500px; margin-left: 500px; } .head { width: 100%; height: 100px; background: pink; /* position: fixed; */ top: 0; left: 0; } </style> </head> <body> <!-- <div class="head"></div> --> <div class="circle-wrap"> <span>当下方的卡片在可视区域内,我的圈圈是绿色,否则是红色</span> <span class="circle"></span> </div> <div class="card-wrap"> <div class="card">我是一个卡片</div> </div> <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/lodash.js"></script> <script> const card = document.querySelector(".card"); const circle = document.querySelector(".circle"); const getBoundingClientRectJudge = () => { let domRect = card.getBoundingClientRect(); let ch = document.documentElement.clientHeight; let cw = document.documentElement.clientWidth; let isInsert = true; if (domRect.bottom < 0 || domRect.top > ch || domRect.right < 0 || domRect.left > cw) { isInsert = false; } let background = null if (isInsert) { background = "green" } else { background = "red" } circle.style.background = background } window.addEventListener("scroll", _.throttle(getBoundingClientRectJudge, 500)) getBoundingClientRectJudge() </script> </body> </html>
由此,我们引出第二种方法,IntersectionObserver。
方法2:IntersectionObserver
用法
eg:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>getBoundingClientRect可视区域</title> <style> * { margin: 0 } body { height: 2000px; width: 3000px; } .circle-wrap { position: fixed; top: 50px; right: 50px; padding: 10px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); width: 140px; background: #fff; } .circle-wrap .circle { display: inline-block; width: 20px; height: 20px; border-radius: 50%; background: red; } .card-wrap { height: 400px; width: 600px; margin-top: 100px; margin-left: 100px; border: 1px solid green; overflow: auto; } .card-wrap .card { width: 200px; height: 200px; padding: 20px; box-sizing: border-box; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); margin-top: 500px; margin-left: 500px; } .head{ width: 100%; height: 100px; background: pink; /* position: fixed; */ top:0; left: 0; } </style> </head> <body> <!-- <div class="head"></div> --> <div class="circle-wrap"> <span>当下方的卡片在可视区域内,我的圈圈是绿色,否则是红色</span> <span class="circle"></span> </div> <div class="card-wrap"> <div class="card">我是一个卡片</div> </div> <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/lodash.js"></script> <script> const card = document.querySelector(".card"); const circle = document.querySelector(".circle"); const observer = new IntersectionObserver((changes) => { // changes是数组 changes.forEach(one => { console.log(one) let isIntersecting = one.isIntersecting let background = null if (isIntersecting) { background = "green" } else { background = "red" } circle.style.background = background }) }) observer.observe(card) // console.log(observer) /* 取消观察特定的元素:observer.unobserve(dom) */ /* 对象停止监听目标 observer.disconnect() */ </script> </body> </html>
补充说明
IntersectionObserver
可以传root
,进一步判断dom
是相对于哪个节点,来判断是否在可视区域内,默认root
是document
。
const observer = new IntersectionObserver((changes) => { console.log(changes) changes.forEach(one => { console.log(one) let isIntersecting = one.isIntersecting let background = null if (isIntersecting) { background = "green" } else { background = "red" } circle.style.background = background }) },{root:document.querySelector(".card-wrap")})
方法3:offsetTop、scrollTop
说明
offsetTop
:元素的上外边框至包含元素的上内边框之间的像素距离,其他方向相同offsetWidth
:元素两端算上外边框的宽度,其他方向相同scrollLeft
和scrollTop
:既可以确定当前元素的滚动状态,也可以设置元素的滚动位置scrollWidth
和scrollHeight
:确定元素内容的实际大小clientWidth
:元素内容区宽度加上左右内边距宽度,即clientWidth = content + padding
clientHeight
:元素内容区高度加上上下内边距高度,即clientHeight = content + padding
使用
公式:
0 <= el.offsetTop - document.documentElement.scrollTop <= viewPortHeight
写法:
function isInViePortOfOne(el){ const viewPortHeight = window.innerHeight || document.documentElement.clientHeight||document.body.clientHeight const offsetTop = el.offsetTop; const scollTop = document.documentElement.scrollTop const top = offsetTop - scollTop; return top <= viewPortHeight && top >= 0 }
以上就是JavaScript判断元素是否在可视区域的三种方法的详细内容,更多关于JavaScript判断元素是否在可视区域的资料请关注脚本之家其它相关文章!