React+TS+IntersectionObserver实现视频懒加载和自动播放功能
作者:码上花甲
为了提高用户体验,网站通常会使用视频来呈现内容。然而,在网站中使用自动播放的视频通常会导致页面加载时间变长,因为用户需要等待更长的时间才能看到内容。为了解决这个问题,我们可以使用懒加载技术来延迟视频的加载,只有在用户滚动页面并且视频进入视口时才开始下载视频资源。同时,为了进一步提高用户体验,当视频进入用户的视野范围时,我们希望视频能够自动播放。
本文将介绍如何使用 React + TypeScript 来通过 IntersectionObserver API 实现这一功能。在正式开始之前,我们先来看一下最终实现的效果图:
实现这一功能的核心在于 IntersectionObserver API。下面我们将简单介绍一下这个 API 的用法。
IntersectionObserver
IntersectionObserver 是浏览器内置的 API,用于监听元素是否交叉或超出了视口(viewport)的变化。这个 API 提供了一种异步观察目标元素的机制,在元素进入或离开视口时触发回调函数。
以下是 IntersectionObserver API 的基本语法:
const observer = new IntersectionObserver(callback, options);
其中 callback
是回调函数,options
是配置选项,用于指定观察器的参数,如视口的大小、元素与视口的交叉比例等。
创建 IntersectionObserver 对象后,我们就可以监听目标元素:
observer.observe(target); // target 是被观察的目标元素
组件卸载时,应取消监听:
observer.unobserve(target);
如果监听了多个元素,可以停止监听所有目标元素:
observer.disconnect();
上面的 disconnect()
方法用于停止所有目标元素的监听,并销毁 IntersectionObserver 对象。
现在,你应该已经了解了 IntersectionObserver API。下面,我们将通过编写一个可扩展的组件来实现效果图演示的功能。
视频播放控制组件
首先,我们定义一个 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
钩子来创建一个 videoRef
引用。我们将通过该引用来判断视频状态、更新视频真实地址、控制视频的播放和暂停功能。
const videoRef = useRef<HTMLVideoElement>(null);
然后,我们使用 useEffect
钩子来创建一个 IntersectionObserver
实例。我们要实现的功能主要就是通过这个实例来实现的。
useEffect(() => { const video = videoRef.current; const options = { rootMargin: "0px", threshold: 0.5, // 指定交叉比例为 50% 时触发回调函数 }; // 创建 IntersectionObserver 实例 const observer = new IntersectionObserver(([entry]) => { // ... }, options); // 监听 video 元素 if (video) { observer.observe(video); } // 组件卸载时取消监听 return () => { observer.unobserve(video as Element); }; }, []);
在 IntersectionObserver
的回调函数中,我们检查视频是否进入视口,如果进入视口,首先要加载视频。如果视频加载完成,就开始播放视频:
if (entry.isIntersecting) { // 当视频进入视口时,开始播放视频 if (video?.readyState === 4) { // 视频已经加载完毕 video?.play(); } else { // 监听视频加载完成事件 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
属性表示视频的加载状态,如果它的值为 4,表示视频已经加载完毕。
如果视频还没有加载完毕,我们就需要等到它加载完成后再开始播放。为了实现这一点,我们在 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", // 用于指定目标元素与根元素(视口)的边缘间的偏移量,以便确定何时触发回调函数。 threshold: 0.5, // 指定交叉比例为 50% 时触发回调函数 }; // 创建 IntersectionObserver 实例 const observer = new IntersectionObserver(([entry]) => { if (entry.isIntersecting) { // 当视频进入视口时,开始播放视频 if (video?.readyState === 4) { // 视频已经加载完毕 video?.play(); } else { // 监听视频加载完成事件 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); // 监听 video 元素 if (video) { observer.observe(video); } // 组件卸载时取消监听 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 来实现一个视频播放控制组件。该组件具有懒加载功能,只有在用户滚动页面且视频进入视口时才开始下载视频资源。同时,当视频进入用户的视野范围时,视频能够自动播放,提高了用户的使用体验。
IntersectionObserver API 提供了一种异步观察目标元素的机制,即在元素进入或离开视口时触发回调函数。这为我们的视频播放控制组件提供了关键的功能。
通过编写这个可扩展的组件,你可以为网站的视频播放功能提供更好的用户体验。同时,我们也了解了如何使用 React + TypeScript 和 IntersectionObserver API 来实现类似的功能,这将为我们今后的开发工作提供更多的思路和帮助。
到此这篇关于React+TS+IntersectionObserver实现视频懒加载和自动播放!的文章就介绍到这了,更多相关React懒加载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!