React videojs 实现自定义组件(视频画质/清晰度切换) 的操作代码

 更新时间:2023年08月28日 11:44:55   作者:Might°  
最近使用videojs作为视频处理第三方库,用来对接m3u8视频类型,这里总结一下自定义组件遇到的问题及实现,感兴趣的朋友跟随小编一起看看吧

前言

最近使用videojs作为视频处理第三方库,用来对接m3u8视频类型。这里总结一下自定义组件遇到的问题及实现,目前看了许多文章也不全,官方文档写的也不是很详细,自己摸索了一段时间陆陆续续完成了,这是实现后的效果.

image.png

样式啥的自己检查后覆盖就行了,没啥说的,重点看看画质切换这个组件如何实现的。最开始我是采用函数组件直接嵌入进去,后面发现是报错的,原因是hook使用范围有误,找了半天也不知道是什么原因。后面采用继承Videojs内的menu组件来实现。

代码实现

option配置如下

 const options: any = {
    controls: true,
    preload: 'auto',
    language: 'zh-CN',
    width: 854,
    height: 480,
    playbackRates: [0.5, 0.75, 1, 1.5, 2], // 倍速数组
    controlBar: {
      children: {
        PlayToggle: true,
        CurrentTimeDisplay: true,
        DurationDisplay: true,
        ProgressControl: true,
        Quality: true,
        PlaybackRateMenuButton: true,
        volumePanel: {
          inline: false,
        },
        PictureInPictureToggle: true,
        FullscreenToggle: true,
      },
    },
  }

video组件

import { ForwardedRef, forwardRef, useEffect, useImperativeHandle, useRef } from 'react'
import videojs from 'video.js'
import Quality from './quality'
import './index.less'
interface videoComProps {
  videoOptions: any
  onReady: (player: any) => void
  src?: string
}
const VideoWrapper = (props: videoComProps, ref: ForwardedRef<any>) => {
  const { videoOptions, onReady, src } = props
  const videoRef = useRef<any>(null)
  const playerRef = useRef<any>(null)
  function toggleTv(obj: any) {
    const player = playerRef?.current
    if (!player) return
    player.src(obj.src)
    player.load(obj.load)
    player.play()
  }
  useEffect(() => {
    if (!playerRef?.current && videoRef.current) {
      // 注册组件  一定要在使用之前注册哦
      videojs.registerComponent('Quality', Quality as any)
      // 初始化video
      const player = (playerRef.current = videojs(videoRef.current, videoOptions, () => {
        onReady(player)
      }))
    }
  }, [videoRef])
  useEffect(() => {
    const player = playerRef.current
    return () => {
      // 组件销毁的时候,销毁视频播放器的实例
      if (player && !player.isDisposed()) {
        player.dispose()
        playerRef.current = null
      }
    }
  }, [playerRef])
  // ref抛出变量
  useImperativeHandle(ref, () => ({
    toggleTv,
  }))
  return (
    <div className="video-wrapper">
      <video
        ref={videoRef}
        className="video-js vjs-big-play-centered"
      >
        <source src={src} />
        {/* <span>视频走丢了,请稍后再试</span> */}
      </video>
    </div>
  )
}
export default forwardRef(VideoWrapper)

自定义组件

// 切换视频清晰度代码
import videoJs from 'video.js'
import { createRoot } from 'react-dom/client'
// 初始化清晰度按钮
const TextTrackMenuItem: any = videoJs.getComponent('TextTrackMenuItem')
const TrackButton: any = videoJs.getComponent('TrackButton')
const videoQuality = '超清,高清,自动'
class QualityTrackItem extends TextTrackMenuItem {
  constructor(player: any, options: any) {
    super(player, options)
    this.mount = this.mount.bind(this)
    player.ready(() => {
      this.mount()
    })
    this.on('dispose', () => {
      this.root.unmount()
    })
    if (options.index === 2) {
      this.addClass('vjs-selected')
    }
  }
  // 切换高清播放源,this 指向被点击QualityTrackItem实例
  handleClick(event: any) {
    // 先将所有选项的选中状态设为未选中
    this.parentComponent_.children_.forEach((c: any) => {
      c.selected(false)
    })
    // 选中当前
    this.selected(true)
    // 选中后修改按钮文本
    const btn = document.querySelector('.vjs-menu-button .vjs-icon-placeholder')
    if (!btn) return
    btn.innerHTML = this.track.label
    // 其他逻辑 通知修改视频源地址进行切换
    console.log('切换视频源')
  }
  mount() {
    this.root = createRoot(this.el()).render(<div>{this.track.label}</div>)
  }
}
// 扩展基类,实现菜单按钮
class QualityTrackButton extends TrackButton {
  constructor(player: any, options: any) {
    super(player, options)
    this.controlText('画质选择')
    this.children()[0].el().firstElementChild.innerText = '自动'
    this.addClass('vjs-quality')
  }
  createItems() {
    const qualityKeyArray = videoQuality.split(',')
    if (qualityKeyArray.length > 0) {
      const result: any = []
      qualityKeyArray.forEach((key, index: number) => {
        result.push(
          new QualityTrackItem(this.player_, {
            track: {
              label: key,
              value: key,
            },
            selectable: true,
            index,
          })
        )
      })
      return result
    } else {
      return []
    }
  }
}
export default QualityTrackButton

可能遇到的问题

1.卸载不了对应事件

  const handleUpdate = useCallback(() => {
    const player = playerRef.current
    //window.document.fullscreenElement检测视频是否正在全屏
    // console.log('播放中,当前时间是', player.currentTime())
    if (player.currentTime() > 10) {
      if (window.document.fullscreenElement) {
        // 如果是全屏 退出全屏
        window.document.exitFullscreen()
      }
      player.currentTime(10)
      setOverlay(true)
      player.pause()
    }
  }, [])
useEffect(() => {
    if (!playerRef?.current && videoRef.current) {
      // 注册组件  一定要在使用之前注册哦
      videojs.registerComponent('Quality', Quality as any)
      // 初始化video
      const player = (playerRef.current = videojs(videoRef.current, videoOptions, () => {
        onReady(player)
      }))
      playFlag && player.on('timeupdate', handleUpdate)
    }
  }, [videoRef])
  // 加入学习
  const handelAddLearn = () => {
    const player = playerRef.current
    player.off('timeupdate', handleUpdate)
    setPlayFlag(false)
    setOverlay(false)
    player.play()
  }

把对应需要卸载的事件采用useCallback进行处理,这样的事件的地址就不会变化造成卸载失效的问题。

到此这篇关于React videojs 实现自定义组件(视频画质/清晰度切换) 的操作代码的文章就介绍到这了,更多相关videojs自定义组件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解React 条件渲染

    详解React 条件渲染

    这篇文章主要介绍了React 条件渲染的相关资料,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • 利用CDN加速react webpack打包后的文件详解

    利用CDN加速react webpack打包后的文件详解

    下面小编就为大家分享一篇利用CDN加速react webpack打包后的文件详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-02-02
  • 使用webpack搭建react开发环境的方法

    使用webpack搭建react开发环境的方法

    本篇文章主要介绍了使用webpack搭建react开发环境的方法,在这篇文章中我们开始利用我们之前所学搭建一个简易的React开发环境,用以巩固我们之前学习的Webpack知识。一起跟随小编过来看看吧
    2018-05-05
  • react-native fetch的具体使用方法

    react-native fetch的具体使用方法

    本篇文章主要介绍了react-native fetch的具体使用方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • React表单容器的通用解决方案

    React表单容器的通用解决方案

    本文主要介绍了React表单容器的通用解决方案,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • 一文教会你用redux实现computed计算属性

    一文教会你用redux实现computed计算属性

    在computed中,可以定义一些属性,即计算属性,下面这篇文章主要给大家介绍了关于如何利用redux实现computed计算属性的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • React 中 setState使用小结

    React 中 setState使用小结

    这篇文章主要介绍了React 中 setState使用小结,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-10-10
  • Redux中异步action与同步action的使用

    Redux中异步action与同步action的使用

    本文主要介绍了Redux中异步action与同步action的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • react render props模式实现组件复用示例

    react render props模式实现组件复用示例

    本文主要介绍了react render props模式实现组件复用示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • react-router中<Link/>的属性详解

    react-router中<Link/>的属性详解

    这篇文章主要给大家介绍了关于react-router中<Link/>属性的相关资料,文中介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-06-06

最新评论