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,您應該會注意到影像在它們進入檢視之前就被檢測並載入。同樣,一個負值意味著在影像已經進入檢視後才會檢測到交叉。
規範
此特性似乎未在任何規範中定義。瀏覽器相容性
載入中…