怎么使用React+TS+IntersectionObserver实现视频懒加载和自动播放功能

服务器   发布日期:2025年04月03日   浏览次数:209

这篇“怎么使用React+TS+IntersectionObserver实现视频懒加载和自动播放功能”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么使用React+TS+IntersectionObserver实现视频懒加载和自动播放功能”文章吧。

IntersectionObserver

IntersectionObserver 是浏览器内置的 API,用于监听元素是否交叉或超出了视口(viewport)的变化。这个 API 提供了一种异步观察目标元素的机制,在元素进入或离开视口时触发回调函数。

以下是 IntersectionObserver API 的基本语法:

  1. const observer = new IntersectionObserver(callback, options);

其中

  1. callback
是回调函数,
  1. options
是配置选项,用于指定观察器的参数,如视口的大小、元素与视口的交叉比例等。

创建 IntersectionObserver 对象后,我们就可以监听目标元素:

  1. observer.observe(target); // target 是被观察的目标元素

组件卸载时,应取消监听:

  1. observer.unobserve(target);

如果监听了多个元素,可以停止监听所有目标元素:

  1. observer.disconnect();

上面的

  1. disconnect()
方法用于停止所有目标元素的监听,并销毁 IntersectionObserver 对象。

现在,你应该已经了解了 IntersectionObserver API。下面,我们将通过编写一个可扩展的组件来实现效果图演示的功能。

视频播放控制组件

首先,我们定义一个

  1. VideoProps
接口,它包含了我们的
  1. Video
组件的属性:
  1. interface VideoProps {
  2. src: string;
  3. width?: number;
  4. height?: number;
  5. className?: string;
  6. }

接下来,我们定义

  1. Video
组件,它接收
  1. src
  1. width
  1. height
  1. className
属性:
  1. const Video: React.FC<VideoProps> = ({
  2. src,
  3. width = 400,
  4. height = 300,
  5. className,
  6. }) => {
  7. // ...
  8. };

  1. Video
组件中,我们通过
  1. useRef
钩子来创建一个
  1. videoRef
引用。我们将通过该引用来判断视频状态、更新视频真实地址、控制视频的播放和暂停功能。
  1. const videoRef = useRef<HTMLVideoElement>(null);

然后,我们使用

  1. useEffect
钩子来创建一个
  1. IntersectionObserver
实例。我们要实现的功能主要就是通过这个实例来实现的。
  1. useEffect(() => {
  2. const video = videoRef.current;
  3. const options = {
  4. rootMargin: "0px",
  5. threshold: 0.5, // 指定交叉比例为 50% 时触发回调函数
  6. };
  7. // 创建 IntersectionObserver 实例
  8. const observer = new IntersectionObserver(([entry]) => {
  9. // ...
  10. }, options);
  11. // 监听 video 元素
  12. if (video) {
  13. observer.observe(video);
  14. }
  15. // 组件卸载时取消监听
  16. return () => {
  17. observer.unobserve(video as Element);
  18. };
  19. }, []);

  1. IntersectionObserver
的回调函数中,我们检查视频是否进入视口,如果进入视口,首先要加载视频。如果视频加载完成,就开始播放视频:
  1. if (entry.isIntersecting) {
  2. // 当视频进入视口时,开始播放视频
  3. if (video?.readyState === 4) {
  4. // 视频已经加载完毕
  5. video?.play();
  6. } else {
  7. // 监听视频加载完成事件
  8. if (video?.dataset.src) {
  9. // 将 data-src 的值赋给 src 属性
  10. video.src = video.dataset.src;
  11. delete video.dataset.src;
  12. video?.addEventListener("loadedmetadata", () => {
  13. video?.play();
  14. });
  15. }
  16. }
  17. } else {
  18. // 当视频离开视口时,暂停视频播放
  19. video?.pause();
  20. }

注意,示例代码中使用了

  1. video?.readyState === 4
来检查视频是否已经加载完毕。
  1. readyState
属性表示视频的加载状态,如果它的值为 4,表示视频已经加载完毕。

如果视频还没有加载完毕,我们就需要等到它加载完成后再开始播放。为了实现这一点,我们在

  1. data-src
属性中存储视频的地址,然后在视频加载完成后再将它赋值给
  1. src
属性。当视频加载完成后,记得要删除
  1. data-src
属性,避免重复加载视频:
  1. if (video?.dataset.src) {
  2. // 将 data-src 的值赋给 src 属性
  3. video.src = video.dataset.src;
  4. delete video.dataset.src;
  5. video?.addEventListener("loadedmetadata", () => {
  6. video?.play();
  7. });
  8. }

下面是最终的代码:

  1. /**
  2. * @description 视频组件
  3. * @param {string} src 视频地址
  4. * @param {number} width 视频宽度
  5. * @param {number} height 视频高度
  6. * @param {string} className 自定义类名
  7. * @returns {JSX.Element}
  8. * @example
  9. * import Video from '@/components/Video';
  10. * <Video src="<https://www.w3schools.com/html/mov_bbb.mp4>" />
  11. */
  12. import React, { useRef, useEffect } from "react";
  13. interface VideoProps {
  14. src: string;
  15. width?: number | string;
  16. height?: number | string;
  17. className?: string;
  18. }
  19. const Video: React.FC<VideoProps> = ({
  20. src,
  21. width = 400,
  22. height = 300,
  23. className,
  24. }) => {
  25. const videoRef = useRef<HTMLVideoElement>(null);
  26. useEffect(() => {
  27. const video = videoRef.current;
  28. const options = {
  29. rootMargin: "0px", // 用于指定目标元素与根元素(视口)的边缘间的偏移量,以便确定何时触发回调函数。
  30. threshold: 0.5, // 指定交叉比例为 50% 时触发回调函数
  31. };
  32. // 创建 IntersectionObserver 实例
  33. const observer = new IntersectionObserver(([entry]) => {
  34. if (entry.isIntersecting) {
  35. // 当视频进入视口时,开始播放视频
  36. if (video?.readyState === 4) {
  37. // 视频已经加载完毕
  38. video?.play();
  39. } else {
  40. // 监听视频加载完成事件
  41. if (video?.dataset.src) {
  42. // 将 data-src 的值赋给 src 属性
  43. video.src = video.dataset.src;
  44. delete video.dataset.src;
  45. video?.addEventListener("loadedmetadata", () => {
  46. video?.play();
  47. });
  48. }
  49. }
  50. } else {
  51. // 当视频离开视口时,暂停视频播放
  52. video?.pause();
  53. }
  54. }, options);
  55. // 监听 video 元素
  56. if (video) {
  57. observer.observe(video);
  58. }
  59. // 组件卸载时取消监听
  60. return () => {
  61. observer.unobserve(video as Element);
  62. };
  63. }, []);
  64. return (
  65. <video
  66. loop
  67. muted
  68. controls
  69. playsInline
  70. width={width}
  71. ref={videoRef}
  72. data-src={src} // 添加 data-src 属性
  73. height={height}
  74. className={className}
  75. />
  76. );
  77. };
  78. export default Video;

以上就是怎么使用React+TS+IntersectionObserver实现视频懒加载和自动播放功能的详细内容,更多关于怎么使用React+TS+IntersectionObserver实现视频懒加载和自动播放功能的资料请关注九品源码其它相关文章!