IntersectionObserver:scrollMargin 属性
IntersectionObserver 接口的只读属性 scrollMargin 为根元素内的所有嵌套 滚动容器 添加了一个边距,如果根元素本身是滚动容器,则也包括根元素。
这会在计算交叉点之前,增大或缩小可滚动容器的裁剪矩形。例如,这可以让您调整滚动容器的边界,即使目标元素的像素尚未在容器的视口中显示,也能将其视为可见;或者,如果目标元素的边缘离容器边界框的边缘太近,则将其视为部分隐藏。
请注意,如果根元素本身也是一个可滚动容器,那么 scrollMargin 和 rootMargin 会被合并,以确定用于计算与目标的交叉点的有效边界矩形。
有关更多信息,请参阅 API 概述中的 “交叉根和滚动边距”。
值
一个字符串,其格式类似于 CSS margin 属性的值。
指定的边距定义了滚动容器裁剪矩形的一个或多个侧边的偏移量。如果在实例化对象时未指定 scrollMargin,则默认为字符串 "0px 0px 0px 0px"。
示例
带有滚动边距的轮播图
此示例定义了一个可滚动框(根元素),其中包含一个最初不可见的图片轮播图。一个在根元素上的观察者会观察轮播图中图像元素目标。当图像元素开始与根元素交叉时,就会加载图像,记录交叉情况,然后移除观察者。
该示例允许您修改 scrollMargin,以查看当轮播图可滚动容器内的目标开始交叉时,这会如何变化。
HTML
下面的代码定义了 root-container <div> 元素,我们将使用它作为交叉观察者的根元素。这又包含一个 <p> 元素,用于“默认”将其他元素推离视口,一个 carousel <div>,以及一个 margin-indicator(用于指示应用于根元素内可滚动元素的边距大小)。
轮播图中的 <img> 元素有一个 data-src 属性,其中包含文件名。在我们的观察者代码中,当每个图像开始与根元素交叉时,我们将使用此属性设置 img.src,这将加载图像。
<div id="root-container">
<p>content before (scroll down to carousel)</p>
<div class="flex-container">
<div class="carousel">
<img
data-src="ballon-portrait.jpg"
class="lazy-carousel-img"
alt="Balloon portrait" />
<img
data-src="balloon-small.jpg"
class="lazy-carousel-img"
alt="balloon-small" />
<img data-src="surfer.jpg" class="lazy-carousel-img" alt="surfer" />
<img
data-src="border-diamonds.png"
class="lazy-carousel-img"
alt="border-diamonds" />
<img data-src="fire.png" class="lazy-carousel-img" alt="fire" />
<img data-src="puppy-header.jpg" class="lazy-carousel-img" alt="puppy" />
<img data-src="moon.jpg" class="lazy-carousel-img" alt="moon" />
<img data-src="rhino.jpg" class="lazy-carousel-img" alt="rhino" />
</div>
<div id="margin-indicator"></div>
</div>
<p>content after</p>
</div>
<div class="controls">
<label>
Set the right margin of the scroll root:
<input id="margin" type="number" value="0" step="5" />px
</label>
</div>
CSS
#root-container {
height: 250px;
overflow-y: auto;
border: solid blue;
}
p {
height: 50vh;
}
.flex-container {
display: flex;
}
#margin-indicator {
position: relative;
height: 100px;
width: 1px;
background-color: red;
opacity: 0.5;
display: flex;
}
.carousel {
width: 300px;
overflow-x: auto;
scroll-snap-type: x mandatory;
display: flex;
border: solid;
/* outline: 200px solid rgba(0, 0, 0, 0.1); */
}
.carousel img {
scroll-snap-stop: always;
scroll-snap-align: start;
display: block;
width: 195px;
height: 99px;
min-width: 195px;
min-height: 99px;
margin-right: 10px;
background-color: #eeeeee; /* Placeholder background */
}
.controls {
margin-top: 10px;
}
JavaScript
代码的第一部分定义了 createImageObserver() 函数,我们使用它来创建 IntersectionObserver 对象并将其分配给 imageObserver 变量。我们使用一个函数,因为观察者选项在构造后无法更改,并且我们希望能够演示不同 scrollMargin 值的影响。
IntersectionObserver 是使用 rootMargin 为空、threshold 接近零,以及 scrollMargin 从 margin 输入值获取值来创建的,该值将应用于可滚动容器的所有侧面。
回调函数会针对所有被观察的目标调用。对于交叉的目标,它会将 img.src 设置为要加载的图像的名称(来自 img.dataset.src),记录交叉情况,然后停止观察图像。
函数末尾的代码在每个图像上调用 IntersectionObserver.observe() 来启动观察者。
const rootContainer = document.getElementById("root-container");
const marginIndicator = document.getElementById("margin-indicator");
const carousel = document.querySelector(".carousel");
const lazyImages = carousel.querySelectorAll(".lazy-carousel-img");
let imageObserver;
function createImageObserver() {
if (imageObserver) {
imageObserver.disconnect();
}
let observerOptions = {
root: rootContainer,
rootMargin: "0px", // No extra margin
scrollMargin: `${margin.valueAsNumber}px`, // No extra margin / Can be set
threshold: 0.01, // Trigger when 1% of the image is visible
};
imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const img = entry.target;
log(`intersect: ${img.dataset.src}`); // Only on first intersection
img.src = `https://mdn.github.io/shared-assets/images/examples/${img.dataset.src}`; // Load image by setting src
img.classList.remove("lazy-carousel-img"); // Remove the class
observer.unobserve(img); // Stop observing once loaded
}
});
}, observerOptions);
if (margin.valueAsNumber < 0) {
marginIndicator.style.width = `${-margin.valueAsNumber}px`;
marginIndicator.style.left = `${margin.valueAsNumber}px`;
marginIndicator.style.backgroundColor = "blue";
} else {
marginIndicator.style.width = `${margin.valueAsNumber}px`;
marginIndicator.style.left = "0px";
marginIndicator.style.backgroundColor = "green";
}
lazyImages.forEach((image) => {
imageObserver.observe(image); // Start observing each image
});
}
下面的代码在开始时以及每次 margin 输入值更改时使用 createImageObserver() 创建观察者。如果不支持 IntersectionObserver 接口,则会立即加载所有图像。
if ("IntersectionObserver" in window) {
createImageObserver();
margin.addEventListener("input", () => {
createImageObserver();
});
} else {
// Fallback for browsers that don't support Intersection Observer
// Loads all images immediately if Intersection Observer is not supported.
lazyImages.forEach((img) => {
img.src = img.dataset.src;
img.classList.remove("lazy-carousel-img");
});
console.warn(
"Intersection Observer not supported. All carousel images loaded.",
);
}
结果
向下滚动以显示轮播图。可见的图像应立即加载。如果您向右滚动轮播图,您应该会注意到,一旦元素可见,图像就会加载。
您可以使用提供的控件更改滚动边距百分比(重置示例后)。如果您设置一个正值(例如 20px),滚动容器的裁剪矩形将增加 20px,您应该会注意到图像在它们进入视图之前就被检测并加载。同样,一个负值意味着在图像已经进入视图后才会检测到交叉。
规范
此特性似乎未在任何规范中定义。浏览器兼容性
加载中…