React+TS+IntersectionObserver實現(xiàn)視頻懶加載和自動播放功能
為了提高用戶體驗,網站通常會使用視頻來呈現(xiàn)內容。然而,在網站中使用自動播放的視頻通常會導致頁面加載時間變長,因為用戶需要等待更長的時間才能看到內容。為了解決這個問題,我們可以使用懶加載技術來延遲視頻的加載,只有在用戶滾動頁面并且視頻進入視口時才開始下載視頻資源。同時,為了進一步提高用戶體驗,當視頻進入用戶的視野范圍時,我們希望視頻能夠自動播放。
本文將介紹如何使用 React + TypeScript 來通過 IntersectionObserver API 實現(xiàn)這一功能。在正式開始之前,我們先來看一下最終實現(xiàn)的效果圖:

實現(xiàn)這一功能的核心在于 IntersectionObserver API。下面我們將簡單介紹一下這個 API 的用法。
IntersectionObserver
IntersectionObserver 是瀏覽器內置的 API,用于監(jiān)聽元素是否交叉或超出了視口(viewport)的變化。這個 API 提供了一種異步觀察目標元素的機制,在元素進入或離開視口時觸發(fā)回調函數(shù)。
以下是 IntersectionObserver API 的基本語法:
const observer = new IntersectionObserver(callback, options);
其中 callback 是回調函數(shù),options 是配置選項,用于指定觀察器的參數(shù),如視口的大小、元素與視口的交叉比例等。
創(chuàng)建 IntersectionObserver 對象后,我們就可以監(jiān)聽目標元素:
observer.observe(target); // target 是被觀察的目標元素
組件卸載時,應取消監(jiān)聽:
observer.unobserve(target);
如果監(jiān)聽了多個元素,可以停止監(jiān)聽所有目標元素:
observer.disconnect();
上面的 disconnect() 方法用于停止所有目標元素的監(jiān)聽,并銷毀 IntersectionObserver 對象。
現(xiàn)在,你應該已經了解了 IntersectionObserver API。下面,我們將通過編寫一個可擴展的組件來實現(xiàn)效果圖演示的功能。
視頻播放控制組件
首先,我們定義一個 VideoProps 接口,它包含了我們的 Video 組件的屬性:
interface VideoProps {
src: string;
width?: number;
height?: number;
className?: string;
}接下來,我們定義 Video 組件,它接收 src、width、height 和 className 屬性:
const Video: React.FC<VideoProps> = ({
src,
width = 400,
height = 300,
className,
}) => {
// ...
};在 Video 組件中,我們通過 useRef 鉤子來創(chuàng)建一個 videoRef 引用。我們將通過該引用來判斷視頻狀態(tài)、更新視頻真實地址、控制視頻的播放和暫停功能。
const videoRef = useRef<HTMLVideoElement>(null);
然后,我們使用 useEffect 鉤子來創(chuàng)建一個 IntersectionObserver 實例。我們要實現(xiàn)的功能主要就是通過這個實例來實現(xiàn)的。
useEffect(() => {
const video = videoRef.current;
const options = {
rootMargin: "0px",
threshold: 0.5, // 指定交叉比例為 50% 時觸發(fā)回調函數(shù)
};
// 創(chuàng)建 IntersectionObserver 實例
const observer = new IntersectionObserver(([entry]) => {
// ...
}, options);
// 監(jiān)聽 video 元素
if (video) {
observer.observe(video);
}
// 組件卸載時取消監(jiān)聽
return () => {
observer.unobserve(video as Element);
};
}, []);在 IntersectionObserver 的回調函數(shù)中,我們檢查視頻是否進入視口,如果進入視口,首先要加載視頻。如果視頻加載完成,就開始播放視頻:
if (entry.isIntersecting) {
// 當視頻進入視口時,開始播放視頻
if (video?.readyState === 4) {
// 視頻已經加載完畢
video?.play();
} else {
// 監(jiān)聽視頻加載完成事件
if (video?.dataset.src) {
// 將 data-src 的值賦給 src 屬性
video.src = video.dataset.src;
delete video.dataset.src;
video?.addEventListener("loadedmetadata", () => {
video?.play();
});
}
}
} else {
// 當視頻離開視口時,暫停視頻播放
video?.pause();
}注意,示例代碼中使用了 video?.readyState === 4 來檢查視頻是否已經加載完畢。readyState 屬性表示視頻的加載狀態(tài),如果它的值為 4,表示視頻已經加載完畢。
如果視頻還沒有加載完畢,我們就需要等到它加載完成后再開始播放。為了實現(xiàn)這一點,我們在 data-src 屬性中存儲視頻的地址,然后在視頻加載完成后再將它賦值給 src 屬性。當視頻加載完成后,記得要刪除 data-src 屬性,避免重復加載視頻:
if (video?.dataset.src) {
// 將 data-src 的值賦給 src 屬性
video.src = video.dataset.src;
delete video.dataset.src;
video?.addEventListener("loadedmetadata", () => {
video?.play();
});
}我們看下加載視頻的效果圖:

在效果圖中可以看到,當視頻進入視口后,開始下載視頻。視頻下載完成后便開始自動播放。當視頻移出視口時,視頻會自動暫停。
至此,這個組件基本就完成了。下面是最終的代碼:
/**
* @description 視頻組件
* @param {string} src 視頻地址
* @param {number} width 視頻寬度
* @param {number} height 視頻高度
* @param {string} className 自定義類名
* @returns {JSX.Element}
* @example
* import Video from '@/components/Video';
* <Video src="<https://www.w3schools.com/html/mov_bbb.mp4>" />
*/
import React, { useRef, useEffect } from "react";
interface VideoProps {
src: string;
width?: number | string;
height?: number | string;
className?: string;
}
const Video: React.FC<VideoProps> = ({
src,
width = 400,
height = 300,
className,
}) => {
const videoRef = useRef<HTMLVideoElement>(null);
useEffect(() => {
const video = videoRef.current;
const options = {
rootMargin: "0px", // 用于指定目標元素與根元素(視口)的邊緣間的偏移量,以便確定何時觸發(fā)回調函數(shù)。
threshold: 0.5, // 指定交叉比例為 50% 時觸發(fā)回調函數(shù)
};
// 創(chuàng)建 IntersectionObserver 實例
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
// 當視頻進入視口時,開始播放視頻
if (video?.readyState === 4) {
// 視頻已經加載完畢
video?.play();
} else {
// 監(jiān)聽視頻加載完成事件
if (video?.dataset.src) {
// 將 data-src 的值賦給 src 屬性
video.src = video.dataset.src;
delete video.dataset.src;
video?.addEventListener("loadedmetadata", () => {
video?.play();
});
}
}
} else {
// 當視頻離開視口時,暫停視頻播放
video?.pause();
}
}, options);
// 監(jiān)聽 video 元素
if (video) {
observer.observe(video);
}
// 組件卸載時取消監(jiān)聽
return () => {
observer.unobserve(video as Element);
};
}, []);
return (
<video
loop
muted
controls
playsInline
width={width}
ref={videoRef}
data-src={src} // 添加 data-src 屬性
height={height}
className={className}
/>
);
};
export default Video;結語
通過本文的介紹,我們學習了如何使用 React + TypeScript 和 IntersectionObserver API 來實現(xiàn)一個視頻播放控制組件。該組件具有懶加載功能,只有在用戶滾動頁面且視頻進入視口時才開始下載視頻資源。同時,當視頻進入用戶的視野范圍時,視頻能夠自動播放,提高了用戶的使用體驗。
IntersectionObserver API 提供了一種異步觀察目標元素的機制,即在元素進入或離開視口時觸發(fā)回調函數(shù)。這為我們的視頻播放控制組件提供了關鍵的功能。
通過編寫這個可擴展的組件,你可以為網站的視頻播放功能提供更好的用戶體驗。同時,我們也了解了如何使用 React + TypeScript 和 IntersectionObserver API 來實現(xiàn)類似的功能,這將為我們今后的開發(fā)工作提供更多的思路和幫助。
到此這篇關于React+TS+IntersectionObserver實現(xiàn)視頻懶加載和自動播放!的文章就介紹到這了,更多相關React懶加載內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
解決React報錯Rendered more hooks than during
這篇文章主要為大家介紹了React報錯Rendered more hooks than during the previous render解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12
教你使用vscode 搭建react-native開發(fā)環(huán)境
本文記錄如何使用vscode打造一個現(xiàn)代化的react-native開發(fā)環(huán)境,旨在提高開發(fā)效率和質量。本文給大家分享我遇到的問題及解決方法,感興趣的朋友跟隨小編一起看看吧2021-07-07
next-redux-wrapper使用細節(jié)及源碼分析
這篇文章主要為大家介紹了next-redux-wrapper使用細節(jié)及源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02
ReactNative實現(xiàn)圖片上傳功能的示例代碼
本篇文章主要介紹了ReactNative實現(xiàn)圖片上傳功能的示例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-07-07
使用react在修改state中的數(shù)組和對象數(shù)據的時候(setState)
這篇文章主要介紹了使用react在修改state中的數(shù)組和對象數(shù)據的時候(setState),具有很好的參考價值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
react native實現(xiàn)往服務器上傳網絡圖片的實例
下面小編就為大家?guī)硪黄猺eact native實現(xiàn)往服務器上傳網絡圖片的實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-08-08

