ממשקי IntersectionObservers מאפשרים לכם לקבל התראות כשרכיב שנמדד נכנס לאזור התצוגה של הדפדפן או יוצא ממנו.
נניח שאתם רוצים לעקוב אחרי מקרים שבהם רכיב ב-DOM נכנס לאזור התצוגה הגלוי. מומלץ לעשות זאת כדי לטעון תמונות באופן מדורג בדיוק בזמן, או כדי לדעת אם המשתמש מביט בבאנר מסוים של המודעה. כדי לעשות זאת, אפשר לחבר את אירוע הגלילה או להשתמש בטיימר תקופתי ולהפעיל את הטלפון getBoundingClientRect()
ברכיב הזה.
עם זאת, הגישה הזו איטית מאוד כי כל קריאה ל-getBoundingClientRect()
מאלצת את הדפדפן לפרוס מחדש את הדף כולו ועלולה לגרום לבעיות רבות באתר שלך. כאשר יודעים שהאתר נטען בתוך iframe ורוצים לדעת מתי המשתמש יכול לראות רכיב, כמעט בלתי אפשרי. המודל של מקור יחיד והדפדפן לא יאפשרו לך לגשת לנתונים מדף האינטרנט שמכיל את ה-iframe. זו בעיה נפוצה במודעות, לדוגמה, שנטענות לעיתים קרובות באמצעות מסגרות iframe.
בדיקת החשיפה הזו ליעילות יותר היא המטרה שתוכננו על ידי IntersectionObserver
, והיא זמינה בכל הדפדפנים המתקדמים. בעזרת IntersectionObserver
אפשר לדעת כשרכיב שנמדד נכנס לאזור התצוגה של הדפדפן או יוצא ממנו.
![חשיפת iframe](https://web.developers.google.cn/static/articles/intersectionobserver/image/iframe-visibility-45640aaa99537.gif?authuser=5&hl=he)
איך יוצרים IntersectionObserver
ממשק ה-API הוא די קטן, וניתן לתאר אותו בצורה הטובה ביותר בעזרת דוגמה:
const io = new IntersectionObserver(entries => {
console.log(entries);
}, {
/* Using default options. Details below */
});
// Start observing an element
io.observe(element);
// Stop observing an element
// io.unobserve(element);
// Disable entire IntersectionObserver
// io.disconnect();
כשמשתמשים באפשרויות ברירת המחדל של IntersectionObserver
, הקריאה החוזרת (callback) תיקרא גם כשהרכיב מופיע באופן חלקי בתצוגה וגם כשהוא עוזב את אזור התצוגה.
אם צריך לצפות במספר רכיבים, אפשר ומומלץ לצפות במספר רכיבים באמצעות אותה מופע IntersectionObserver
באמצעות קריאה ל-observe()
מספר פעמים.
הפרמטר entries
מועבר לקריאה החוזרת (callback), שהוא מערך של אובייקטים של IntersectionObserverEntry
. כל אובייקט כזה מכיל נתוני חיתוך מעודכנים של אחד מהאלמנטים המתועדים.
🔽[IntersectionObserverEntry]
time: 3893.92
🔽rootBounds: ClientRect
bottom: 920
height: 1024
left: 0
right: 1024
top: 0
width: 920
🔽boundingClientRect: ClientRect
// ...
🔽intersectionRect: ClientRect
// ...
intersectionRatio: 0.54
🔽target: div#observee
// ...
הערך rootBounds
הוא התוצאה של קריאה ל-getBoundingClientRect()
ברכיב הבסיסי (root), שהוא אזור התצוגה כברירת מחדל. הערך boundingClientRect
הוא התוצאה של הפקודה getBoundingClientRect()
ברכיב שנמדד. intersectionRect
הוא החיתוך של שני המלבנים האלה ומראה בפועל איזה חלק של הרכיב שנמדד גלוי. המונח intersectionRatio
קשור באופן הדוק, והוא מציין כמה מהאלמנט גלוי. בעזרת המידע הזה, מעכשיו אפשר להטמיע תכונות כמו 'טעינה בזמן אמת' של נכסים לפני שהם מוצגים במסך. ביעילות.
![יחס צומת.](https://web.developers.google.cn/static/articles/intersectionobserver/image/intersection-ratio-cc2e11cc70559.png?authuser=5&hl=he)
IntersectionObserver
מעבירים את הנתונים שלהם באופן אסינכרוני, וקוד הקריאה החוזרת יפעל ב-thread הראשי. בנוסף, במפרט עצמו כתוב ש-IntersectionObserver
הטמעות צריכות להשתמש ב-requestIdleCallback()
. המשמעות היא שהקריאה להתקשרות חזרה שסיפקתם היא בעדיפות נמוכה ותבוצע על ידי הדפדפן במהלך זמן חוסר פעילות. זוהי החלטה מושכלת לגבי התכנון.
גלילה ב-div
אני לא מת על גלילה בתוך אלמנט, אבל אני לא כאן כדי לשפוט, וגם לא IntersectionObserver
. האובייקט options
משתמש באפשרות root
שמאפשרת להגדיר חלופה לאזור התצוגה בתור הרמה הבסיסית (root). חשוב לזכור שהפרמטר root
צריך להיות ישות האב של כל הרכיבים המתועדים.
שילוב של כל הפריטים!
לא. מפתח גרוע! זה לא שימוש מושכל במחזורי המעבד (CPU) של המשתמש. נחשוב על גלילה אינסופית כדוגמה: בתרחיש הזה, בהחלט מומלץ להוסיף סנטינלים ל-DOM ולצפות בהם (ולמחזר!) אותם. צריך להוסיף סנטינל קרוב לפריט האחרון בגלילה האינסופית. כשהסנטינל מוצג, אפשר להשתמש בקריאה חוזרת (callback) כדי לטעון נתונים, ליצור את הפריטים הבאים, לצרף אותם ל-DOM ולמקם אותם מחדש בהתאם. אם ממחזרים את הסנטינל בצורה תקינה, אין צורך בקריאה נוספת ל-observe()
. IntersectionObserver
ממשיך לעבוד.
![גלילה מתמשכת](https://web.developers.google.cn/static/articles/intersectionobserver/image/infinite-scroller-f23f2b90aa6bd.png?authuser=5&hl=he)
עדכונים נוספים בבקשה
כפי שצוין קודם, הקריאה החוזרת (callback) תופעל פעם אחת כשהרכיב שנמדד יוצג באופן חלקי, ופעם נוספת אחרי שהוא יצא מאזור התצוגה. כך מקבלים תשובה מ-IntersectionObserver
לשאלה "האם רכיב X בתצוגה?". עם זאת, במקרים מסוימים ייתכן שזה לא יהיה מספיק.
כאן האפשרות threshold
נכנסת לתוקף. היא מאפשרת להגדיר מערך של ערכי סף של intersectionRatio
. תתבצע קריאה חוזרת לקריאה חוזרת (callback) בכל פעם ש-intersectionRatio
יחרוג מאחד מהערכים האלה. ערך ברירת המחדל של threshold
הוא [0]
, והוא מסביר את התנהגות ברירת המחדל. אם נעדכן את threshold
ל-[0, 0.25, 0.5, 0.75, 1]
, נקבל הודעה בכל פעם שרבעון נוסף של הרכיב יוצג:
![אנימציית סף.](https://web.developers.google.cn/static/articles/intersectionobserver/image/threshold-animation-818bf785c4e2d.gif?authuser=5&hl=he)
יש אפשרויות נוספות?
נכון לעכשיו, יש רק אפשרות אחת נוספת לאלו שצוינו למעלה. rootMargin
מאפשר לציין את השוליים של הרמה הבסיסית (root) וכך להגדיל או לכווץ את האזור שמשמש לצמתים. השוליים האלה מצוינים באמצעות מחרוזת בסגנון CSS, á la "10px 20px 30px 40px"
, ומציינים את השוליים העליונים, הימניים, התחתון והשמאלי בהתאמה. לסיכום, מבנה האפשרויות של IntersectionObserver
כולל את האפשרויות הבאות:
new IntersectionObserver(entries => {/* … */}, {
// The root to use for intersection.
// If not provided, use the top-level document's viewport.
root: null,
// Same as margin, can be 1, 2, 3 or 4 components, possibly negative lengths.
// If an explicit root element is specified, components may be percentages of the
// root element size. If no explicit root element is specified, using a
// percentage is an error.
rootMargin: "0px",
// Threshold(s) at which to trigger callback, specified as a ratio, or list of
// ratios, of (visible area / total area) of the observed element (hence all
// entries must be in the range [0, 1]). Callback will be invoked when the
// visible ratio of the observed element crosses a threshold in the list.
threshold: [0],
});
<iframe>
קסם
הנכסים IntersectionObserver
תוכננו במיוחד עם התייחסות לווידג'טים של שירותי מודעות ושל רשתות חברתיות, שמשתמשים לעיתים קרובות ברכיבי <iframe>
וכדאי לדעת אם הם מוצגים. אם <iframe>
מזהה אחד מהרכיבים שלו, גם גלילה ב-<iframe>
וגם גלילה בחלון שמכיל את התג <iframe>
יפעילו את הקריאה החוזרת בזמנים המתאימים. לעומת זאת, במקרה השני, הערך rootBounds
יוגדר לערך null
כדי למנוע דליפת נתונים בין מקורות.
מה נושא IntersectionObserver
לא?
חשוב לזכור ש-IntersectionObserver
הוא לא פיקסל מושלם ולא זמן אחזור קצר. השימוש בהם להטמעת הפרעות כמו אנימציות התלויות בגלילה עלול להיכשל, מאחר שהנתונים יהיו כבר לא מעודכנים עד שתתחיל להשתמש בהם. ההסבר כולל פרטים נוספים על התרחישים המקוריים של השימוש ב-IntersectionObserver
.
כמה עבודה אפשר לבצע בקריאה החוזרת?
תשובה קצרה ומתוקה: אם משקיעים יותר מדי זמן בקריאה החוזרת (callback), הם גורמים לעיכוב בעדכון האפליקציה — כל השיטות הנפוצות רלוונטיות.
המשך והצליב את הרכיבים שלך
תמיכת הדפדפן ב-IntersectionObserver
טובה, כפי שהיא זמינה בכל הדפדפנים המתקדמים. אם יש צורך, אפשר להשתמש ב-polyfill בדפדפנים ישנים יותר, והוא זמין במאגר של WICG. כמובן שלא תיהנו מיתרונות הביצועים אם תשתמשו ב-polyfill שהטמעה מותאמת תעניק לכם.
אפשר להתחיל להשתמש ב-IntersectionObserver
כבר עכשיו. ספרו לנו מה חשבתם.