我如何使用 Intersection Observers 来判断何时有东西占据了整个视口?
How can I use Intersection Observers to tell when something is taking up the entire viewport?
当整个元素都在视口内时,交集观察者很容易分辨出来。代码大致是这样的:
// get an element
const thingIWantEntirelyInView = $("#Thing")[0];
const checkInView = new IntersectionObserver((event) => {
console.log("It's in view");
}, {
root: null, // viewport
threshold: 1.0,
});
checkInView.observe(thingIWantEntirelyInView);
不过,我想不通的是如何翻转它,因此它不太像包含而更像封面。我想知道我的元素(大于视口)何时完全覆盖屏幕。
我试过调换上面null
和thingIWantEntirelyInView
的位置,但是没用。
我还尝试在页面中添加一个位置固定的 height: 100vh; width: 100vw
元素并检查与之的交集,但交集观察器似乎无法处理没有父子关系的两个元素?也许我写错了代码,但这里有一个例子:
const thingIWantFillingView = document.getElementById("BigScrolly");
const viewPort = document.getElementById("ViewPort");
// what I tried
const checkInView = new IntersectionObserver((event) => {
console.log("This never seems to happen never happen");
}, {
root: thingIWantFillingView,
threshold: 0.5,
});
// when the viewport is at least half inside BigScrolly
checkInView.observe(viewPort);
// example of the thing I don't want
const checkTouchView = new IntersectionObserver((event) => {
console.log("It has touched the viewport");
}, {
root: null,
threshold: 0,
});
// when BigScrolly has touched the viewport
checkTouchView.observe(thingIWantFillingView);
#ViewPort {
position: fixed;
height: 100vh;
width: 100vw;
top: 0px;
left: 0px;
pointer-events: none;
border: 2px solid red;
box-sizing: border-box;
}
#SomePreviousThing {
height: 100vh;
}
#BigScrolly {
height: 300vh;
background: linear-gradient(#FFEEEA, #222);
}
<div id="ViewPort"></div>
<div id="SomePreviousThing">
Ignore this section, scroll down.
</div>
<div id="BigScrolly"></div>
如何使用 Intersection Observers 判断我的元素之一何时完全覆盖屏幕?
想出一个解决方案:我在 BigScrolly 中有一个 100vh
高的粘性元素(确保包裹在绝对定位元素中以否定它在流中的位置)。只要我完全滚动到该部分,它就会占据整个视图。
const coverChecker = document.querySelector(".CoverChecker");
// what I tried
const checkInView = new IntersectionObserver((event) => {
const coverage = event[0].intersectionRatio;
if (coverage >= 1) {
console.log("BigScrolly covers the viewport");
} else {
console.log("Coverage", event[0].intersectionRatio);
}
}, {
root: null,
threshold: [0, 0.25, 0.5, 0.75, 1.0],
});
// when the viewport is at least half inside BigScrolly
checkInView.observe(coverChecker);
.Positioner {
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
pointer-events: none;
}
.CoverChecker {
position: sticky;
height: 95vh;
width: 95vw;
border: 2px solid red;
box-sizing: border-box;
top: 2px;
}
.OtherSection {
height: 100vh;
}
#BigScrolly {
position: relative;
height: 300vh;
padding: 20px;
background: linear-gradient(#FFEEEA, #222);
}
<div class="OtherSection">
Ignore this section, scroll down.
</div>
<div id="BigScrolly">
<div class="Positioner">
<div class="CoverChecker"></div>
</div>
This is some text
</div>
<div class="OtherSection">
Ignore this section, scroll tup.
</div>
您可以通过简单地检查 intersectionRect.top
是否为零(并检查是否存在任何交集)来实现此目的:
new IntersectionObserver((entries) => {
entries.forEach( entry => {
if (entry.intersectionRatio == 0) {
console.log('not visible at all')
return
}
if (entry.intersectionRect.top == 0) {
console.log('at the top of the viewport')
return
}
console.log('partially visible — not at the top of the viewport')
})
})
这是一个完整的示例 - 我用它来反转浮动页面 header,而页面的深色部分位于 header 下方:https://jsfiddle.net/okvtm7gc/
当整个元素都在视口内时,交集观察者很容易分辨出来。代码大致是这样的:
// get an element
const thingIWantEntirelyInView = $("#Thing")[0];
const checkInView = new IntersectionObserver((event) => {
console.log("It's in view");
}, {
root: null, // viewport
threshold: 1.0,
});
checkInView.observe(thingIWantEntirelyInView);
不过,我想不通的是如何翻转它,因此它不太像包含而更像封面。我想知道我的元素(大于视口)何时完全覆盖屏幕。
我试过调换上面null
和thingIWantEntirelyInView
的位置,但是没用。
我还尝试在页面中添加一个位置固定的 height: 100vh; width: 100vw
元素并检查与之的交集,但交集观察器似乎无法处理没有父子关系的两个元素?也许我写错了代码,但这里有一个例子:
const thingIWantFillingView = document.getElementById("BigScrolly");
const viewPort = document.getElementById("ViewPort");
// what I tried
const checkInView = new IntersectionObserver((event) => {
console.log("This never seems to happen never happen");
}, {
root: thingIWantFillingView,
threshold: 0.5,
});
// when the viewport is at least half inside BigScrolly
checkInView.observe(viewPort);
// example of the thing I don't want
const checkTouchView = new IntersectionObserver((event) => {
console.log("It has touched the viewport");
}, {
root: null,
threshold: 0,
});
// when BigScrolly has touched the viewport
checkTouchView.observe(thingIWantFillingView);
#ViewPort {
position: fixed;
height: 100vh;
width: 100vw;
top: 0px;
left: 0px;
pointer-events: none;
border: 2px solid red;
box-sizing: border-box;
}
#SomePreviousThing {
height: 100vh;
}
#BigScrolly {
height: 300vh;
background: linear-gradient(#FFEEEA, #222);
}
<div id="ViewPort"></div>
<div id="SomePreviousThing">
Ignore this section, scroll down.
</div>
<div id="BigScrolly"></div>
如何使用 Intersection Observers 判断我的元素之一何时完全覆盖屏幕?
想出一个解决方案:我在 BigScrolly 中有一个 100vh
高的粘性元素(确保包裹在绝对定位元素中以否定它在流中的位置)。只要我完全滚动到该部分,它就会占据整个视图。
const coverChecker = document.querySelector(".CoverChecker");
// what I tried
const checkInView = new IntersectionObserver((event) => {
const coverage = event[0].intersectionRatio;
if (coverage >= 1) {
console.log("BigScrolly covers the viewport");
} else {
console.log("Coverage", event[0].intersectionRatio);
}
}, {
root: null,
threshold: [0, 0.25, 0.5, 0.75, 1.0],
});
// when the viewport is at least half inside BigScrolly
checkInView.observe(coverChecker);
.Positioner {
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
pointer-events: none;
}
.CoverChecker {
position: sticky;
height: 95vh;
width: 95vw;
border: 2px solid red;
box-sizing: border-box;
top: 2px;
}
.OtherSection {
height: 100vh;
}
#BigScrolly {
position: relative;
height: 300vh;
padding: 20px;
background: linear-gradient(#FFEEEA, #222);
}
<div class="OtherSection">
Ignore this section, scroll down.
</div>
<div id="BigScrolly">
<div class="Positioner">
<div class="CoverChecker"></div>
</div>
This is some text
</div>
<div class="OtherSection">
Ignore this section, scroll tup.
</div>
您可以通过简单地检查 intersectionRect.top
是否为零(并检查是否存在任何交集)来实现此目的:
new IntersectionObserver((entries) => {
entries.forEach( entry => {
if (entry.intersectionRatio == 0) {
console.log('not visible at all')
return
}
if (entry.intersectionRect.top == 0) {
console.log('at the top of the viewport')
return
}
console.log('partially visible — not at the top of the viewport')
})
})
这是一个完整的示例 - 我用它来反转浮动页面 header,而页面的深色部分位于 header 下方:https://jsfiddle.net/okvtm7gc/