ממשקי IntersectionObserver מאפשרים לכם לדעת מתי רכיב נצפה נכנס לאזור התצוגה של הדפדפן או יוצא ממנו.
נניח שאתם רוצים לעקוב אחרי רכיב ב-DOM שנכנס לאזור התצוגה הגלוי. יכול להיות שתרצו לעשות את זה כדי לטעון תמונות בטעינה מדורגת (lazy loading) בדיוק בזמן, או כי אתם צריכים לדעת אם המשתמש באמת מסתכל על מודעת באנר מסוימת. כדי לעשות את זה, אפשר להגדיר אירוע גלילה או להשתמש בטיימר תקופתי ולהפעיל את getBoundingClientRect() ברכיב הזה.
עם זאת, הגישה הזו איטית מאוד, כי כל קריאה ל-getBoundingClientRect() מאלצת את הדפדפן לפרוס מחדש את כל הדף, וזה יגרום לבעיות משמעותיות בביצועים של האתר. המצב הופך לכמעט בלתי אפשרי כשאתם יודעים שהאתר שלכם נטען בתוך iframe ואתם רוצים לדעת מתי המשתמש יכול לראות רכיב מסוים. מודל המקור היחיד והדפדפן לא יאפשרו לכם לגשת לנתונים כלשהם מדף האינטרנט שמכיל את ה-iframe. זו בעיה נפוצה במודעות, למשל, שלעיתים קרובות נטענות באמצעות רכיבי iframe.
המאפיין IntersectionObserver נועד לייעל את בדיקת החשיפה הזו, והוא זמין בכל הדפדפנים המודרניים. IntersectionObserver מאפשר לכם לדעת מתי רכיב נצפה נכנס או יוצא מאזור התצוגה של הדפדפן.
איך יוצרים 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() ברכיב הבסיס, שהוא אזור התצוגה כברירת מחדל. boundingClientRect היא התוצאה של getBoundingClientRect() שנקראת ברכיב שנצפה. intersectionRect הוא החיתוך של שני המלבנים האלה, והוא מציין איזה חלק מהרכיב הנצפה גלוי. המדד intersectionRatio קשור באופן הדוק, והוא מציין כמה מהרכיב גלוי. בעזרת המידע הזה, אתם יכולים להטמיע תכונות כמו טעינת נכסים ברגע האחרון לפני שהם מוצגים במסך. ביעילות.
IntersectionObservers מספקים את הנתונים שלהם באופן אסינכרוני, וקוד ה-callback יפעל ב-thread הראשי. בנוסף, במפרט כתוב שההטמעות של IntersectionObserver צריכות להשתמש ב-requestIdleCallback(). המשמעות היא שהקריאה לפונקציית ה-callback שסיפקתם היא בעדיפות נמוכה, והדפדפן יבצע אותה בזמן חוסר פעילות. זו החלטה עיצובית מודעת.
רכיבי div שניתן לגלול
אני לא אוהב לגלול בתוך רכיב, אבל אני לא כאן כדי לשפוט, וגם לא IntersectionObserver. האובייקט options מקבל את האפשרות root, שמאפשרת להגדיר חלופה לאזור התצוגה כרכיב הבסיס. חשוב לזכור שהרכיב root צריך להיות רכיב אב של כל הרכיבים שנצפו.
חיתוך של כל הדברים!
לא! מפתח רע! זה לא שימוש מושכל במחזורי המעבד (CPU) של המשתמש. לדוגמה, נחשוב על גלילה אינסופית: בתרחיש הזה, מומלץ מאוד להוסיף sentinels ל-DOM ולצפות בהם (ולמחזר אותם!). כדאי להוסיף סמן קרוב לפריט האחרון בגלילה האינסופית. כשהרכיב הזה מופיע, אפשר להשתמש בקריאה החוזרת כדי לטעון נתונים, ליצור את הפריטים הבאים, לצרף אותם ל-DOM ולשנות את המיקום של הרכיב בהתאם. אם ממחזרים את ה-sentinel כמו שצריך, לא צריך קריאה נוספת ל-observe(). ה-IntersectionObserver ממשיך לפעול.
אני רוצה לקבל עוד עדכונים
כמו שצוין קודם, פונקציית ה-callback תופעל פעם אחת כשהרכיב הנצפה יופיע באופן חלקי, ופעם נוספת כשהוא ייצא מאזור התצוגה. כך IntersectionObserver נותן לכם תשובה לשאלה "האם רכיב X מוצג?". עם זאת, במקרים מסוימים זה לא מספיק.
כאן נכנסת לתמונה האפשרות threshold. היא מאפשרת להגדיר מערך של ערכי סף של intersectionRatio. הקריאה החוזרת תופעל בכל פעם ש-intersectionRatio יחצה את אחד מהערכים האלה. ערך ברירת המחדל של threshold הוא [0], וזה מסביר את פעולת ברירת המחדל. אם נשנה את threshold ל-[0, 0.25, 0.5, 0.75, 1], נקבל התראה בכל פעם שרבע נוסף מהרכיב יהפוך לגלוי:
יש אפשרויות נוספות?
נכון לעכשיו, יש רק אפשרות אחת נוספת לאפשרויות שמפורטות למעלה. rootMargin מאפשר לכם לציין את השוליים של הרכיב הראשי, וכך להגדיל או להקטין את האזור שמשמש לחיתוכים. השוליים האלה מצוינים באמצעות מחרוזת בסגנון CSS, כמו "10px 20px 30px 40px", שמציינת את השוליים העליונים, הימניים, התחתונים והשמאליים, בהתאמה. לסיכום, המבנה IntersectionObserver options מציע את האפשרויות הבאות:
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> קסם
IntersectionObservers were designed specifically with ads services and social network widgets in mind, which frequently use <iframe> elements and could benefit from knowing whether they are in view. אם <iframe> צופה באחד מהרכיבים שלו, גם גלילה של <iframe> וגם גלילה של החלון שמכיל את <iframe> יפעילו את הקריאה החוזרת (callback) בזמנים המתאימים. עם זאת, במקרה השני, הערך של rootBounds יוגדר כ-null כדי למנוע זליגת נתונים בין מקורות.
מה IntersectionObserver לא כולל?
חשוב לזכור ש-IntersectionObserver לא נועד להיות מושלם מבחינת הפיקסלים או לספק זמן אחזור נמוך. אם תשתמשו בהם כדי להטמיע פעולות כמו אנימציות שתלויות בגלילה, סביר להניח שהן ייכשלו, כי הנתונים יהיו לא עדכניים עד שתשתמשו בהם. במסמך ההסבר יש פרטים נוספים על תרחישי השימוש המקוריים של IntersectionObserver.
כמה עבודה אפשר לעשות בקריאה החוזרת (callback)?
קצר וקולע: אם תבזבזו יותר מדי זמן על הקריאה החוזרת, האפליקציה תתעכב – כל השיטות הנפוצות רלוונטיות.
עכשיו אפשר להצליב בין האלמנטים
התמיכה של הדפדפן ב-IntersectionObserver טובה, כי היא זמינה בכל הדפדפנים המודרניים. אם צריך, אפשר להשתמש ב-polyfill בדפדפנים ישנים יותר, והוא זמין במאגר של WICG. ברור שלא תקבלו את יתרונות הביצועים של שימוש ב-polyfill הזה, שהטמעה מקורית הייתה נותנת לכם.
אפשר להתחיל להשתמש ב-IntersectionObserver כבר עכשיו. נשמח לשמוע מה גיליתם.