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

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

Browser Support

  • Chrome: 51.
  • Edge: 15.
  • Firefox: 55.
  • Safari: 12.1.

Source

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

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

ระบบจะส่งพารามิเตอร์ entries ไปยัง Callback ซึ่งเป็นอาร์เรย์ของออบเจ็กต์ IntersectionObserverEntry ออบเจ็กต์แต่ละรายการจะมีข้อมูล Intersection ที่อัปเดตแล้วสำหรับองค์ประกอบที่สังเกตการณ์รายการใดรายการหนึ่ง

🔽[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 จะส่งข้อมูลแบบอะซิงโครนัส และโค้ด Callback จะทำงานในเทรดหลัก นอกจากนี้ ข้อกำหนดระบุว่าการติดตั้งใช้งาน IntersectionObserver ควรใช้ requestIdleCallback() ซึ่งหมายความว่าการเรียกใช้ Callback ที่คุณระบุไว้มีลำดับความสำคัญต่ำ และเบราว์เซอร์จะดำเนินการในระหว่างที่ไม่มีการใช้งาน ซึ่งเป็นการตัดสินใจด้านการออกแบบโดยเจตนา

Div ที่เลื่อนได้

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

Intersect all the things!

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

การเลื่อนได้ไม่รู้จบ

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

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

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

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

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

ปัจจุบันมีตัวเลือกเพิ่มเติมเพียงตัวเลือกเดียวจากรายการข้างต้น 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 ได้มากน้อยเพียงใด

สั้นและกระชับ: การใช้เวลามากเกินไปใน Callback จะทำให้แอปของคุณล่าช้า ซึ่งแนวทางปฏิบัติทั่วไปทั้งหมดจะมีผล

เริ่มตัดองค์ประกอบต่างๆ ได้เลย

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

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