文章目錄
- 1、前言
- 2、代碼實現
- 3、使用場景
- 4、兼容性
- 5、成熟的Hooks推薦
1、前言
IntersectionObserver 是瀏覽器原生提供的一個Api。可以"觀察"我們的元素是否可見,原理是判斷目標元素與可見區域的交叉比例,所以也被稱為"交叉觀察器"。本文通過一個Demo代碼,講解如何使用IntersectionObserver,來實現根據目標元素可見度的交互效果。并附有兼容性,使用場景,完整代碼實現,以及成熟的Hooks推薦。
2、代碼實現
下面代碼(React 18)是使用 IntersectionObserver 來監聽列表元素的可見度,當卡片元素完全進入瀏覽器視口時,會標記該元素為活動狀態;當元素離開視口時,取消活動狀態。
- 代碼
import { useEffect, useRef, useState } from 'react'
import moduleStyle from './index.module.scss'/*** @description Demo*/
export default function DemoPage() {// #region 數據const [dataList, setDataList] = useState<T_Any[]>([])const observer = useRef<T_Any>(null)// #endregion// #region 邏輯/*** @description 初始化模擬請求數據*/useEffect(() => {setTimeout(() => {const list = [...Array(10)].map((_, index) => {return { value: (index + 1).toString(), isActive: false }})setDataList(list)}, 1000)}, [])/*** @description 監聽*/useEffect(() => {observer.current = new IntersectionObserver((entries) => {entries.forEach((entry, index) => {if (entry.isIntersecting) {const tempList = [...dataList]tempList[index].isActive = truesetDataList(tempList)} else {const tempList = [...dataList]tempList[index].isActive = falsesetDataList(tempList)}})},{root: null,threshold: 1.0 // 當可見度達到100%時觸發})const cardElements = document.querySelectorAll('.card')cardElements.forEach((el) => observer.current.observe(el))return () => {if (observer.current) {observer.current.disconnect()}}}, [dataList])// #endregion// #region 視圖return (<div className={moduleStyle['demo-wrapper']}><div className={`scrollbar-none ${moduleStyle['list-wrapper']}`}>{dataList.map((item) => (<div key={item.value} className={`card ${moduleStyle['item-wrapper']} ${item.isActive ? moduleStyle['active'] : ''}`}>{item.value}</div>))}</div></div>)// #endregion
}
-
dataList:是一個狀態變量,用于存儲模擬請求得到的數據列表。每個數據項包含 value 和 isActive 兩個屬性,value 是元素的標識,isActive 表示元素是否處于活動狀態。
-
observer:是一個 useRef 創建的引用,用于存儲 IntersectionObserver 實例。
-
第一個 useEffect 鉤子:用于模擬異步請求數據。在組件掛載后,通過 setTimeout 模擬接口 1 秒的延遲,生成包含 10 個元素的列表,并更新 dataList 狀態。
-
第二個 useEffect 鉤子用于初始化 IntersectionObserver。當 dataList 發生變化時,創建一個新的 IntersectionObserver 實例,該實例會監聽所有具有 card 類名的元素。當元素完全進入視口(可見度達到 100%)時,將其 isActive 屬性設置為 true;當元素離開視口時,將 isActive 屬性設置為 false。同時,在組件卸載時,斷開 IntersectionObserver 的連接,避免內存泄漏。
-
樣式
.demo-wrapper {width: 100%;height: 100%;padding: 16px;.list-wrapper {display: flex;align-items: center;justify-content: flex-start;flex-wrap: wrap;gap: 16px;width: 100%;height: 100%;overflow-y: auto;.item-wrapper {display: flex;align-items: center;justify-content: center;width: calc(50% - 8px);height: 320px;color: #ffffff;font-size: 24px;background-color: #cccccc;transition: ease 0.3s;border-radius: 8px;overflow: hidden;}.active {background-color: #6212d6 !important;}}
}
3、使用場景
- 懶加載圖片:在圖片較多的頁面中,可以使用 IntersectionObserver 監聽圖片元素的可見性。當圖片元素進入視口時,再加載圖片,從而減少初始加載時的資源消耗,提高頁面性能。
- 無限滾動加載:在社交網站、新聞列表等場景中,當用戶滾動頁面接近底部時,通過監聽底部元素的可見性,觸發加載更多數據的操作,實現無限滾動加載的效果。
- 動畫觸發:當某個元素進入視口時,觸發動畫效果,增強頁面的交互性和視覺效果。例如,元素淡入、滑動等動畫。
4、兼容性
環境 | 版本 | 支持情況 |
---|---|---|
Chrome | 51+ | 支持 |
Firefox | 55+ | 支持 |
Edge | 79+(新版本基于Chromium) | 支持 |
Safari | 12.1+ | 支持 |
iOS Safari | 13+ | 支持 |
Opera | 38+ | 支持 |
Safari on macOS | 12.1+ | 支持 |
Android Browser | 通常跟隨WebView版本 | 需要檢查具體設備 |
Chrome for Android | 51+ | 支持 |
如果不支持,可以使用 IntersectionObserver polyfill 來實現兼容性支持。
5、成熟的Hooks推薦
-
Vue
- useElementVisibility
-
React
- useInViewport
本次分享就到這兒啦,我是鵬多多,如果您看了覺得有幫助,歡迎評論,關注,點贊,轉發,我們下次見~
往期文章
- flutter-使用extended_image操作圖片的加載和狀態處理以及緩存和下載
- flutter-制作可縮放底部彈出抽屜評論區效果
- flutter-實現Tabs吸頂的PageView效果
- Vue2全家桶+Element搭建的PC端在線音樂網站
- 助你上手Vue3全家桶之Vue3教程
- 助你上手Vue3全家桶之VueX4教程
- 助你上手Vue3全家桶之Vue-Router4教程
- 超詳細!Vue的九種通信方式
- 超詳細!Vuex手把手教程
- 使用nvm管理node.js版本以及更換npm淘寶鏡像源
- vue中利用.env文件存儲全局環境變量,以及配置vue啟動和打包命令
個人主頁
- CSDN
- GitHub
- 簡書
- 博客園
- 掘金