IntersectionObserver' กำลังปรากฏตัว

IntersectionObservers จะแจ้งให้คุณทราบเมื่อองค์ประกอบที่สังเกตได้เข้าหรือออกจากวิวพอร์ตของเบราว์เซอร์

การสนับสนุนเบราว์เซอร์

  • 51
  • 15
  • 55
  • 12.1

แหล่งที่มา

สมมติว่าคุณต้องการติดตามเมื่อองค์ประกอบใน DOM เข้าสู่วิวพอร์ตที่มองเห็นได้ คุณอาจต้องการทำเช่นนี้เพื่อให้สามารถโหลดรูปภาพแบบ Lazy Loading ได้ทันเวลา หรือเนื่องจากต้องการทราบว่าผู้ใช้กำลังดูแบนเนอร์โฆษณาหนึ่งๆ อยู่จริงๆ หรือไม่ ซึ่งทำได้โดยการบันทึกเหตุการณ์การเลื่อนหรือใช้ตัวจับเวลาถอยหลังเป็นระยะแล้วเรียกใช้ getBoundingClientRect() ในองค์ประกอบนั้น

อย่างไรก็ตาม วิธีการนี้ช้ามากเนื่องจากการเรียก getBoundingClientRect() แต่ละครั้งบังคับให้เบราว์เซอร์ออกแบบหน้าเว็บทั้งหน้าใหม่ และจะทำให้เกิดความยุ่งยากในเว็บไซต์อย่างมาก กรณีต่างๆ จะเกิดขึ้นไม่ได้หากคุณรู้ว่ากำลังโหลดเว็บไซต์ภายใน iframe และคุณต้องการทราบว่าผู้ใช้จะเห็นองค์ประกอบเมื่อใด โมเดลต้นทางเดียวและเบราว์เซอร์จะไม่ให้คุณเข้าถึงข้อมูลใดๆ จากหน้าเว็บที่มี iframe ซึ่งเป็นปัญหาที่พบบ่อยสำหรับโฆษณาที่โหลดบ่อยโดยใช้ iframe

เราออกแบบการทดสอบการแสดงผลนี้ให้มีประสิทธิภาพมากขึ้นIntersectionObserverและใช้ในเบราว์เซอร์สมัยใหม่ทั้งหมด IntersectionObserver จะแจ้งให้คุณทราบเมื่อองค์ประกอบที่สังเกตได้เข้าหรือออกจากวิวพอร์ตของเบราว์เซอร์

การแสดง iframe

วิธีสร้าง 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 ระบบจะเรียกใช้โค้ดเรียกกลับทั้งเมื่อองค์ประกอบเข้ามาอยู่ในมุมมองบางส่วนและเมื่อออกจากวิวพอร์ตโดยสมบูรณ์

หากคุณต้องสังเกตหลายองค์ประกอบ ก็เป็นไปได้และขอแนะนำให้สังเกตองค์ประกอบหลายรายการโดยใช้อินสแตนซ์ IntersectionObserver เดียวกันด้วยการเรียกใช้ observe() หลายครั้ง

ระบบจะส่งพารามิเตอร์ entries ไปยังโค้ดเรียกกลับซึ่งเป็นอาร์เรย์ของออบเจ็กต์ 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 เกี่ยวข้องอย่างใกล้ชิด และบอกให้ทราบว่าองค์ประกอบปรากฏมากน้อยเพียงใด ซึ่งจะช่วยให้คุณใช้งานฟีเจอร์ต่างๆ ได้ เช่น การโหลดเนื้อหาได้ทันท่วงทีก่อนที่เนื้อหาเหล่านั้นจะปรากฏให้เห็นบนหน้าจอ อย่างมีประสิทธิภาพ

อัตราส่วนสี่แยก

IntersectionObserver จะส่งข้อมูลแบบไม่พร้อมกัน และโค้ดเรียกกลับจะทำงานในเทรดหลัก นอกจากนี้ จริงๆ แล้วข้อกำหนดระบุว่าการติดตั้งใช้งาน IntersectionObserver ควรใช้ requestIdleCallback() ซึ่งหมายความว่าการเรียกกลับที่คุณระบุจะมีลำดับความสำคัญต่ำ และจะดำเนินการโดยเบราว์เซอร์ในช่วงที่ไม่มีการใช้งาน นี่คือการตัดสินใจเกี่ยวกับการออกแบบอย่างมีสติ

การเลื่อน div

ฉันไม่ชอบการเลื่อนองค์ประกอบภายในองค์ประกอบ แต่ก็ไม่พร้อมที่จะตัดสินและ IntersectionObserver ก็เช่นกัน ออบเจ็กต์ options จะใช้ตัวเลือก root ที่ช่วยให้คุณกำหนดทางเลือกสำหรับวิวพอร์ตเป็นรูทได้ โปรดทราบว่า root ต้องเป็นระดับบนขององค์ประกอบที่พบทั้งหมด

ตัดกันทุกอย่างเลย!

ไม่เอาด้วยหรอก นักพัฒนาซอฟต์แวร์แย่! ซึ่งไม่ใช่การคำนึงถึงการใช้งานรอบ CPU ของผู้ใช้ มาลองพิจารณาตัวเลื่อนที่ไม่รู้จบเป็นตัวอย่าง ในสถานการณ์ดังกล่าว เราแนะนำให้เพิ่ม sentinels ไปยัง DOM และสังเกต (และรีไซเคิล) สิ่งเหล่านี้ คุณควรเพิ่มเซนทิเนลใกล้กับรายการสุดท้ายในแถบเลื่อนที่ไม่สิ้นสุด เมื่อผู้ที่เห็นได้เข้ามาอยู่ในมุมมองแล้ว คุณจะใช้โค้ดเรียกกลับเพื่อโหลดข้อมูล สร้างรายการถัดไป แนบรายการดังกล่าวกับ DOM และเปลี่ยนตำแหน่งของความรู้สึกได้ตามความเหมาะสม หากคุณรีไซเคิล Sentinel ได้อย่างถูกต้อง ก็ไม่จำเป็นต้องโทรหา observe() เพิ่มเติม IntersectionObserver ทำงานต่อไป

ตัวเลื่อนได้ไม่รู้จบ

โปรดรับข้อมูลอัปเดตเพิ่มเติม

ดังที่กล่าวไว้ก่อนหน้านี้ โค้ดเรียกกลับจะทริกเกอร์เพียงครั้งเดียวเมื่อองค์ประกอบที่สังเกตได้เข้ามาอยู่ในมุมมองบางส่วน และอีกครั้งเมื่อองค์ประกอบออกจากวิวพอร์ตไปแล้ว วิธีนี้ช่วยให้ IntersectionObserver ตอบคำถามที่ว่า "องค์ประกอบ X อยู่ในมุมมองไหม" อย่างไรก็ตาม ในบางกรณีการใช้งานอาจไม่เพียงพอ

ซึ่งนั่นคือเหตุผลที่ตัวเลือก threshold จะเข้ามามีบทบาท ซึ่งช่วยให้คุณกำหนดอาร์เรย์ของเกณฑ์ intersectionRatio ได้ ระบบจะเรียกโค้ดเรียกกลับทุกครั้งที่ intersectionRatio ข้ามค่าใดค่าหนึ่งต่อไปนี้ ค่าเริ่มต้นสำหรับ threshold คือ [0] ซึ่งอธิบายถึงลักษณะการทำงานเริ่มต้น หากเราเปลี่ยน threshold เป็น [0, 0.25, 0.5, 0.75, 1] เราจะได้รับการแจ้งเตือนทุกครั้งที่มีการมองเห็นองค์ประกอบเพิ่มเติม 1 ใน 4 ส่วน

ภาพเคลื่อนไหวของเกณฑ์

มีตัวเลือกอื่นๆ อีกไหม

ปัจจุบันมีตัวเลือกเพิ่มเติมเพียงรายการเดียวเท่านั้นสำหรับรายการที่ระบุไว้ข้างต้น rootMargin ช่วยให้คุณระบุระยะขอบของรูทได้อย่างมีประสิทธิภาพ ซึ่งช่วยให้คุณขยายหรือย่อพื้นที่ที่ใช้สำหรับทางแยกได้อย่างมีประสิทธิภาพ ระยะขอบเหล่านี้ระบุโดยใช้สตริงรูปแบบ 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 ไม่ได้เกิดจากการที่พิกเซลไม่สมบูรณ์หรือเวลาในการตอบสนองต่ำ การใช้เทมเพลตเหล่านี้ใช้ความพยายามอย่างภาพเคลื่อนไหวที่ต้องขึ้นอยู่กับการเลื่อนมักจะล้มเหลว เนื่องจากข้อมูลจะพูดยาก เพราะข้อมูลจะล้าสมัยไปแล้วเมื่อถึงเวลาที่คุณจะได้ใช้งาน ผู้อธิบายมีรายละเอียดเพิ่มเติมเกี่ยวกับ Use Case เดิมสำหรับ IntersectionObserver

ฉันจะทำอะไรได้บ้างในการติดต่อกลับ

Short 'n Sweet: การใช้เวลาในการโทรกลับมากเกินไปจะทำให้แอปล่าช้าตามแนวทางปฏิบัติทั่วไปทั้งหมด

ออกไปและตัดองค์ประกอบต่างๆ ของคุณ

การสนับสนุนเบราว์เซอร์สำหรับ IntersectionObserver นั้นดี เนื่องจากพร้อมใช้งานในเบราว์เซอร์รุ่นใหม่ๆ หากจำเป็น คุณสามารถใช้ Polyfill ได้ในเบราว์เซอร์รุ่นเก่าและอยู่ในที่เก็บของ WICG แน่นอนว่าคุณจะไม่ได้รับประโยชน์ด้านประสิทธิภาพเมื่อใช้ Polyfill ที่การติดตั้งแบบเนทีฟจะได้รับประโยชน์

คุณเริ่มใช้ IntersectionObserver ได้แล้ววันนี้ บอกให้เราทราบว่าคุณคิดอย่างไร