IntersectionObservers จะแจ้งให้คุณทราบเมื่อองค์ประกอบที่พบเข้าหรือออกจากวิวพอร์ตของเบราว์เซอร์
สมมติว่าคุณต้องการติดตามเมื่อองค์ประกอบใน DOM เข้าสู่วิวพอร์ตที่มองเห็นได้ คุณควรทำเช่นนี้เพื่อให้สามารถโหลดรูปภาพได้ทันท่วงที หรือเนื่องจากคุณต้องการทราบว่าผู้ใช้กำลังดูแบนเนอร์โฆษณาบางอย่างอยู่จริงหรือไม่ ซึ่งทำได้โดยการเชื่อมต่อกับเหตุการณ์การเลื่อนหรือใช้ตัวจับเวลาเป็นระยะและโทรหา getBoundingClientRect()
ในองค์ประกอบนั้น
อย่างไรก็ตาม วิธีนี้ทำได้ช้าเนื่องจากการเรียก getBoundingClientRect()
แต่ละครั้งจะบังคับให้เบราว์เซอร์จัดเลย์เอาต์หน้าเว็บทั้งหมดและจะทำให้เกิดการกระตุกที่เห็นได้ชัดในเว็บไซต์ กรณีแทบจะเป็นไปไม่ได้เลยเมื่อคุณทราบว่าเว็บไซต์ของคุณกำลังโหลดใน iframe และคุณต้องการทราบว่าผู้ใช้จะเห็นองค์ประกอบเมื่อใด โมเดลต้นทางเดียวและเบราว์เซอร์จะไม่อนุญาตให้คุณเข้าถึงข้อมูลใดๆ จากหน้าเว็บที่มี iframe นี่เป็นปัญหาทั่วไป ตัวอย่างเช่น โฆษณามักจะโหลดโดยใช้ iframe
การทำให้การทดสอบการมองเห็นนี้มีประสิทธิภาพมากขึ้นคือสิ่งที่ IntersectionObserver
ออกแบบมาเพื่อ และมีอยู่ในเบราว์เซอร์สมัยใหม่ทั้งหมด IntersectionObserver
จะแจ้งให้คุณทราบเมื่อองค์ประกอบที่พบเข้าหรือออกจากวิวพอร์ตของเบราว์เซอร์
![การแสดง iframe](https://web.dev/static/articles/intersectionobserver/image/iframe-visibility-45640aaa99537.gif?authuser=5&hl=th)
วิธีสร้าง 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
คือจุดร่วมของสี่เหลี่ยม 2 รูปนี้ และบอกคุณว่าส่วนใดขององค์ประกอบที่พบนั้นสามารถมองเห็นได้อย่างมีประสิทธิภาพ intersectionRatio
เกี่ยวข้องกันอย่างใกล้ชิดและบอกคุณว่าองค์ประกอบที่มองเห็นได้มากน้อยเพียงใด เมื่อมีข้อมูลนี้ คุณจะสามารถใช้งานฟีเจอร์ต่างๆ เช่น การโหลดเนื้อหาในเวลาเดียวก่อนที่เนื้อหาจะแสดงบนหน้าจอ อย่างมีประสิทธิภาพ
![อัตราส่วนสี่แยก](https://web.dev/static/articles/intersectionobserver/image/intersection-ratio-cc2e11cc70559.png?authuser=5&hl=th)
IntersectionObserver
จะส่งข้อมูลแบบไม่พร้อมกันและโค้ด Callback จะทำงานในเทรดหลัก นอกจากนี้ ข้อกำหนดยังระบุด้วยว่าการติดตั้งใช้งาน IntersectionObserver
ควรใช้ requestIdleCallback()
ซึ่งหมายความว่าการติดต่อกลับที่คุณให้มาจะมีลำดับความสำคัญต่ำและจะดำเนินการโดยเบราว์เซอร์ในระหว่างที่ไม่มีความเคลื่อนไหว นี่คือการตัดสินใจออกแบบอย่างรอบคอบ
div แบบเลื่อน
ไม่ค่อยชอบเลื่อนในองค์ประกอบเท่าไร ก็ไม่ได้อยากตัดสินและ IntersectionObserver
ก็เช่นกัน ออบเจ็กต์ options
จะใช้ตัวเลือก root
ที่ช่วยให้คุณกำหนดทางเลือกอื่นแทนวิวพอร์ตเป็นรูทของคุณ โปรดทราบว่า root
ต้องเป็นระดับบนขององค์ประกอบที่พบทั้งหมด
ตัดทุกสิ่งให้หมด!
ไม่เอาด้วยหรอก นักพัฒนาซอฟต์แวร์ไม่เก่ง! การทำเช่นนี้ไม่ได้คำนึงถึงการใช้งานรอบ CPU ของผู้ใช้ ลองนึกถึงแถบเลื่อนได้ไม่รู้จบเป็นตัวอย่าง ในสถานการณ์ดังกล่าว เราแนะนำให้เพิ่ม sentinels ลงใน DOM และสังเกต (และรีไซเคิล!) เหล่านั้น คุณควรเพิ่มคำสังเกตใกล้กับรายการสุดท้ายในการเลื่อนได้ไม่รู้จบ เมื่อผู้ฟังเห็น คุณสามารถใช้ Callback เพื่อโหลดข้อมูล สร้างรายการถัดไป แนบรายการดังกล่าวกับ DOM และเปลี่ยนตำแหน่งคำสังเกตให้สอดคล้องกัน หากนำผู้ดูแลกลับมาใช้ใหม่อย่างเหมาะสม ก็ไม่จำเป็นต้องโทรหา observe()
เพิ่มเติม IntersectionObserver
ยังคงทำงานต่อไป
![ตัวเลื่อนได้ไม่รู้จบ](https://web.dev/static/articles/intersectionobserver/image/infinite-scroller-f23f2b90aa6bd.png?authuser=5&hl=th)
โปรดติดตามข้อมูลอัปเดตเพิ่มเติม
ดังที่กล่าวไว้ก่อนหน้านี้ การเรียกกลับจะทริกเกอร์ 1 ครั้งเมื่อองค์ประกอบที่สังเกตพบเห็นได้บางส่วน และอีกครั้งเมื่อออกจากวิวพอร์ต วิธีนี้จะทำให้ IntersectionObserver
ตอบคำถามที่ว่า "มองเห็นองค์ประกอบ X อยู่ไหม" อย่างไรก็ตาม ในบาง Use Case อาจไม่เพียงพอ
เราจึงเลือกใช้ตัวเลือก threshold
ซึ่งจะช่วยให้คุณกำหนดอาร์เรย์ของเกณฑ์ intersectionRatio
ได้ ระบบจะเรียกการติดต่อกลับของคุณทุกครั้งที่ intersectionRatio
ข้ามค่าใดค่าหนึ่งเหล่านี้ ค่าเริ่มต้นสำหรับ threshold
คือ [0]
ซึ่งอธิบายลักษณะการทำงานเริ่มต้น หากเราเปลี่ยน threshold
เป็น [0, 0.25, 0.5, 0.75, 1]
เราจะได้รับแจ้งทุกครั้งที่มีการเห็นองค์ประกอบอีก 1 ใน 4 ส่วน
![ภาพเคลื่อนไหวของเกณฑ์](https://web.dev/static/articles/intersectionobserver/image/threshold-animation-818bf785c4e2d.gif?authuser=5&hl=th)
มีตัวเลือกอื่นๆ อีกไหม
ขณะนี้ มีตัวเลือกเพิ่มเติมเพียง 1 รายการสำหรับตัวเลือกข้างต้น rootMargin
ให้คุณระบุระยะขอบของราก ซึ่งทำให้คุณสามารถขยายหรือย่อพื้นที่ที่ใช้สำหรับทางแยกได้อย่างมีประสิทธิภาพ ระยะขอบเหล่านี้ระบุโดยใช้สตริงรูปแบบ CSS ซึ่งก็คือ "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>
จะทริกเกอร์ Callback ในเวลาที่เหมาะสม แต่ในกรณีหลัง ระบบจะตั้งค่า rootBounds
เป็น null
เพื่อหลีกเลี่ยงการรั่วไหลของข้อมูลข้ามต้นทาง
IntersectionObserver
ไม่ได้เกี่ยวกับอะไร
โปรดทราบว่า IntersectionObserver
ไม่ได้เจตนาให้พิกเซลสมบูรณ์แบบและไม่มีเวลาในการตอบสนองต่ำ การใช้โมเดลดังกล่าวเพื่อใช้งานด้านต่างๆ เช่น ภาพเคลื่อนไหวที่เป็นแบบเลื่อนได้จึงจะล้มเหลว เนื่องจากข้อมูลจะไม่อัปเดต (บอกมาตรงๆ) เมื่อถึงเวลาที่คุณจะใช้งาน คำอธิบายมีรายละเอียดเพิ่มเติมเกี่ยวกับกรณีการใช้งานเดิมสำหรับ IntersectionObserver
ฉันสามารถทำได้มากเพียงใดในการโทรกลับ
ไม่มากไม่น้อย: การใช้เวลาใน Callback มากเกินไปจะทำให้แอปล่าช้า - เป็นไปตามแนวทางปฏิบัติทั่วไปทั้งหมด
เดินออกไปและตัดธาตุของคุณออก
การรองรับเบราว์เซอร์ IntersectionObserver
นั้นอยู่ในระดับดี เนื่องจากมีให้ใช้งานในเบราว์เซอร์รุ่นใหม่ทั้งหมด หากจำเป็น คุณสามารถใช้ Polyfill ในเบราว์เซอร์รุ่นเก่าและมีอยู่ในที่เก็บของ WICG แน่นอนว่าคุณจะไม่ได้รับประโยชน์ด้านประสิทธิภาพจากการใช้ Polyfill เหมือนมาจากการใช้งานแบบเนทีฟ
คุณสามารถเริ่มใช้ IntersectionObserver
ได้ทันที บอกเราว่าคุณคิดเห็นอย่างไร