JavaScript判斷元素是否在可視區(qū)域的三種方法
方法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是否在可視區(qū)域內。
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可視區(qū)域</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>當下方的卡片在可視區(qū)域內,我的圈圈是綠色,否則是紅色</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節(jié)點,它只身處在一個滾動條的情況下。什么意思呢,就是它所有的祖先節(jié)點,加起來的滾動條只有1個,如果它父節(jié)點有滾動條,父父節(jié)點也有滾動條,那這種方法就不好用了,請看示例:
下面展示的結果是錯誤的,圈圈應該是紅色才對。

<!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可視區(qū)域</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>當下方的卡片在可視區(qū)域內,我的圈圈是綠色,否則是紅色</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可視區(qū)域</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>當下方的卡片在可視區(qū)域內,我的圈圈是綠色,否則是紅色</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是數(shù)組
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) */
/* 對象停止監(jiān)聽目標 observer.disconnect() */
</script>
</body>
</html>
補充說明
IntersectionObserver可以傳root,進一步判斷dom是相對于哪個節(jié)點,來判斷是否在可視區(qū)域內,默認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:既可以確定當前元素的滾動狀態(tài),也可以設置元素的滾動位置scrollWidth和scrollHeight:確定元素內容的實際大小clientWidth:元素內容區(qū)寬度加上左右內邊距寬度,即clientWidth = content + paddingclientHeight:元素內容區(qū)高度加上上下內邊距高度,即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判斷元素是否在可視區(qū)域的三種方法的詳細內容,更多關于JavaScript判斷元素是否在可視區(qū)域的資料請關注腳本之家其它相關文章!
相關文章
javascript十個最常用的自定義函數(shù)(中文版)
如果不使用類庫或者沒有自己的類庫,儲備一些常用函數(shù)總是有好處的。2009-09-09
ES6(ECMAScript 6)新特性之模板字符串用法分析
這篇文章主要介紹了ES6(ECMAScript 6)新特性之模板字符串用法,簡單介紹了ES6模板字符串的概念、功能并結合實例形式分析了ES6模板字符串的用法,需要的朋友可以參考下2017-04-04
微信小程序實現(xiàn)注冊登錄功能(表單校驗、錯誤提示)
這篇文章主要介紹了微信小程序 實現(xiàn)注冊、登錄功能(表單校驗、錯誤提示),本文通過代碼給大家詳細介紹,需要的朋友可以參考下2019-12-12

