react+video.js h5自定义视频暂停图标

目录

参考网址

效果图,暂停时显示暂停图标,播放时隐藏暂停图标

代码说明,代码传入url后,可直接复制使用

VideoPausedIcon.ts 组件

VideoCom.tsx

Video.module.less


参考网址

 在Video.js播放器中定制自己的组件 - acgtofe

效果图,暂停时显示暂停图标,播放时隐藏暂停图标

代码说明,代码传入url后,可直接复制使用

注意:videojs升级后,不能用extend创建组件,需要按下方代码建一个组件

VideoPausedIcon.ts 组件
import videojs from "video.js";

const Component: any = videojs.getComponent("Component");

export class VideoPausedIcon extends Component {
  constructor(player: any, options: any) {
    super(player, options);
    // 监听,暂停播放,显示播放按钮
    player.on("pause", () => {
      this.visible = true;
      const el = this.el();
      el.className = "vjs-define-paused";
    });
    // 监听,开始播放,隐藏播放按钮,通过videojs自带的 vjs-hidden 类
    player.on("play", () => {
      this.visible = false;
      const el = this.el();
      el.className = "vjs-define-paused vjs-hidden";
    });
    this.on("touchstart", this.handleTouchStart);
    this.on("touchend", this.handleTouchEnd);
    // 如果需要在web端使用,必须,不兼容的话,web端点击按钮就不会暂停/播放
    this.on("click", (e: any) => this.handleClick(e, player));
  }

  createEl() {
    let pauseIcon = videojs.dom.createEl("div", {
      className: "vjs-define-paused",
      tabIndex: -1,
    });
    !this.visible && videojs.dom.appendContent(pauseIcon, "");
    return pauseIcon;
  }

  handleTouchStart(e: any) {
    // 此处必须,不然点击按钮不能播放/暂停
    e.stopPropagation();
  }

  handleTouchEnd(e: any) {
    // 此处必须,不然点击按钮不能播放/暂停
    e.stopPropagation();
  }

  handleClick(e: any, player: any) {
    e.stopPropagation();
    if (!player) {
      return;
    }
    const paused = player.paused();
    if (paused) {
      player.play();
    } else {
      player.pause();
    }
  }
}
VideoCom.tsx
import React, { useEffect } from "react";
import videojs from "video.js";
import "video.js/dist/video-js.css";
import styles from "./Video.module.less";
import { VideoPausedIcon } from "./VideoPausedIcon";

interface IProps {
  url: string;
}

const VideoCom: React.FC<IProps> = (props: any) => {
  const videoRef = React.useRef<any>(null);
  const playerRef = React.useRef<any>(null);

  useEffect(() => {
    const player: any = playerRef && playerRef.current;
    return () => {
      if (player && !player.isDisposed()) {
        player.dispose();
        playerRef.current = null;
      }
    };
  }, [playerRef]);

  useEffect(() => {
    if (!props.url) {
      return;
    }
    let options: any = {
      controlBar: {
        fullscreenToggle: true,
        pictureInPictureToggle: false,
        volumePanel: false,
        playToggle: false,
      },
      muted: false,
      controls: true, //进度条
      autoplay: false, //自动播放
      loop: false, //是否循环
      languages: {
        "zh-CN": new URL(`video.js/dist/lang/zh-CN.json`, import.meta.url).href,
      },
      language: "zh-CN",
      preload: "auto",
      nodownload: true,
      sources: [{ src: props.url, type: "video/mp4" }],
    };

    // Make sure Video.js player is only initialized once
    if (!playerRef || !playerRef.current) {
      // The Video.js player needs to be _inside_ the component el for React 18 Strict Mode.
      const videoElement = document.createElement("video-js");
      videoRef &&
        videoRef.current &&
        videoRef.current.appendChild(videoElement);

      playerRef.current = videojs(videoElement, options, () => {
        console.log("player is ready");
        const player: any = playerRef.current;
        player.on("error", (err: any) => {
          console.log("source load fail");
          // message.error("视频源请求出错");
        });
        let touchStartTime = 0;
        let touchEndTime = 0;
        player.on("touchstart", (e: any) => {
          touchStartTime = new Date().getTime();
        });
        player.on("touchend", (e: any) => {
          touchEndTime = new Date().getTime();
          if (touchEndTime - touchStartTime < 300) {
            const paused = player.paused();
            if (paused) {
              player.play();
            } else {
              player.pause();
            }
          }
        });
      });
      createPausedIcon();
    } else {
      const player: any = playerRef.current;
      player.src(options.sources);
    }
  }, [
    props.url,
    playerRef,
    videoRef
  ]);

  const createPausedIcon = () => {
    const player = playerRef && playerRef.current;
    if (!player) {
      return;
    }
    const Component: any = videojs.getComponent("Component");
    Component.registerComponent("VideoPausedIcon", VideoPausedIcon);
    const options = {};
    const properIndex = player
      .children()
      .indexOf(player.getChild("BigPlayButton"));
    player.addChild("VideoPausedIcon", options, properIndex);
  };

  return (
    <div className={styles.container}>
      <div className={styles.videoBox} ref={videoRef}></div>
    </div>
  );
};

export default VideoCom;
Video.module.less
.container {
  width: 100%;
  height: 100%;

  .videoBox {
    width: 100%;
    height: 100%;

    :global {
      .video-js {
        width: 100%;
        height: 100%;

        .vjs-big-play-button {
          display: none;
        }

        .vjs-define-paused {
          width: 30px;
          height: 28px;
          background: rgba(43, 63, 46, 0.7);
          border: 1px solid rgb(0, 255, 140);
          border-radius: 10px;
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          transition: all .4s;

          &::after {
            display: block;
            content: '';
            position: absolute;
            top: 50%;
            left: calc(50% + 5px);
            transform: translate(-50%, -50%);
            border-top: 5px solid;
            border-bottom: 5px solid;
            border-left: 8px solid;
            border-right: 8px solid;
            border-color: transparent;
            border-left-color: rgb(0, 255, 140);
          }
        }
      }
    }
  }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/155266.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

nodejs+vue教室管理系统的设计与实现-微信小程序-安卓-python-PHP-计算机毕业设计

用户 用户管理&#xff1a;查看&#xff0c;修改自己的个人信息 教室预约&#xff1a;可以预约今天明天的教室&#xff0c;按着时间段预约&#xff08;可多选&#xff09;&#xff0c;如果当前时间超过预约时间段不能预约该时间段的教室 预约教室的时候要有个预约用途&#xff…

所见即所得的动画效果:Animate.css

我们可以在集成Animate.css来改善界面的用户体验&#xff0c;省掉大量手写css动画的时间。 官网&#xff1a;Animate.css 使用 1、安装依赖 npm install animate.css --save2、引入依赖 import animate.css;3、在项目中使用 在class类名上animate__animated是必须的&#x…

腾讯云服务器新用户购买优惠多少钱?腾讯云新用户购买优惠

对于新用户来说&#xff0c;腾讯云服务器更是提供了一系列的优惠活动&#xff0c;让你在购买时享受到更多的优惠。那么&#xff0c;腾讯云服务器新用户购买优惠多少钱呢&#xff1f;接下来&#xff0c;让我们一起来了解一下。 腾讯云双十一领9999代金券 https://1111.mian100.…

ActiveMQ

目录 ActiveMQ简介 ActiveMQ安装 原生JMS API操作ActiveMQ SpringBoot与ActiveMQ整合 ActiveMQ消息组成与高级特性 ActiveMQ企业面试经典问题总结 ActiveMQ简介 消息中间件应用场景 异步处理 应用解耦 流量削锋 异步处理 场景说明&#xff1a;用户注册&#xff0c;需要执行…

iApp祁天社区UI成品源码 功能齐全的社区应用

iApp祁天社区UI成品源码是一个非常实用的资源&#xff0c;提供了完整的源代码&#xff0c;可以帮助您快速搭建一个功能齐全的社区应用。 这个源码具有丰富的UI设计&#xff0c;经过精心调整和优化&#xff0c;确保用户体验流畅而舒适。它不仅具备基本的社区功能&#xff0c;如…

MFC保存窗口客户区为图片

首先的窗口输出一些内容&#xff1b; 菜单单击函数代码&#xff1b; void CgetmypicView::OnTestGetmypic() {// TODO: 在此添加命令处理程序代码HWND hwnd this->GetSafeHwnd();HDC hDC ::GetWindowDC(hwnd);//获取DC RECT rect;::GetClientRect(hwnd, &rect)…

Mysql 索引优化——Explain

文章目录 Explain 简介Explain 概念Explain 示例 Explain 中列的含义idselect_typetabletypepossible_keyskeykey_lenrefrowExtra 索引最佳实践1.全值匹配2.最左前缀原则3.避免计算、函数、类型转换导致索引失效4.范围条件右边的索引列失效5.尽量使用覆盖索引 Explain 简介 Ex…

软件自动化测试作用简析,为什么要选择第三方软件测评机构?

软件自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。通常&#xff0c;在设计了测试用例并通过评审之后&#xff0c;由测试人员根据测试用例中描述的规程一步步执行测试&#xff0c;得到实际结果与期望结果的比较。 一、自动化测试的作用   1.测试效能大幅度提…

数据结构与算法【队列】的Java实现

队列&#xff1a;以顺序的方式维护的一组数据集合&#xff0c;在一端添加数据&#xff0c;从另一端移除数据。习惯来说&#xff0c;添加的一端称为尾&#xff0c;移除的一端称为头。 通用接口 public interface Queue<E> {/*** 插入队列*/boolean offer(E value);/*** 从…

2023年05月 Python(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 明明每天坚持背英语单词,他建立了英语单词错题本文件“mistakes.txt”,将每天记错的单词增加到该文件中,下列打开文件的语句最合适的是?( ) A: f = open(“mistakes.txt”) B: …

【论文阅读】A Survey on Video Diffusion Models

视频扩散模型&#xff08;Video Diffusion Model&#xff09;最新综述GitHub 论文汇总-A Survey on Video Diffusion Models。 paper&#xff1a;[2310.10647] A Survey on Video Diffusion Models (arxiv.org) 0. Abstract 本文介绍了AIGC时代视频扩散模型的全面回顾。简要介…

Git-概念与架构

GIT-概念与架构 一、背景和起源二、版本控制系统1.版本控制分类1.1 集中式版本控制1.2 分布式版本控制 2.Git和SVN对比2.1 SVN2.2 GIT 三、GIT框架1.工作区&#xff08;working directory&#xff09;2.暂存区&#xff08;staging area&#xff09;3.本地仓库&#xff08;local…

机器视觉公司怎么可能养我这闲人,连软件加密狗都用不起,项目都用盗版,为什么​?

正版价值观我是认同的&#xff0c;但是同行也不用软件加密狗&#xff0c;你让我承担过多的设备成本&#xff0c;终端客户不愿意承担加密狗的成本&#xff0c;公司更不愿意去承担&#xff0c;许多机器视觉公司“零元购”&#xff0c;机器视觉软件加密狗都用不起&#xff0c;项目…

51单片机应用从零开始(五)·加减乘除运算

51单片机应用从零开始&#xff08;一&#xff09;-CSDN博客 51单片机应用从零开始&#xff08;二&#xff09;-CSDN博客 51单片机应用从零开始&#xff08;三&#xff09;-CSDN博客 51单片机应用从零开始&#xff08;四&#xff09;-CSDN博客 详解 KEIL C51 软件的使用建立工程…

微机原理_10

一、单项选择题(本大题共15小题,每小题3分,共45分。在每小题给出的四个备选项中,选出一个正确的答案。&#xff09; 1,将二进制数110110.01转换为十六进制为(&#xff09; A. 66.1H B. 36.4H C. 66.4 D. 36.2 2,一台计算机的字长是4个字节,含义是(&#xff09; A.能处理的最大…

基于STM32微控制器的巡线小车控制研究

## 一、引言 巡线小车是一种常见的智能车型&#xff0c;通常用于参加各类智能车比赛或者教学实验。本文将基于STM32微控制器对巡线小车进行控制研究&#xff0c;主要包括硬件设计和软件编程两个方面。通过该研究&#xff0c;将实现让巡线小车沿着指定轨迹巡线行驶&#xff0c;并…

LEEDCODE 220 存在重复元素3

class Solution { public:int getId(int a, int valuediff){// 值// return a/(valuediff1);return a < 0 ? (a ) -) / (valuediff 1) - 1 : a / (valuediff 1);}public: unordered_map<int, int> bucket;bool containsNearbyAlmostDuplicate(vector<int>&am…

基于SSM的学生疫情信息管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

多维时序 | MATLAB实现PSO-GRU-Attention粒子群优化门控循环单元融合注意力机制的多变量时间序列预测

多维时序 | MATLAB实现PSO-GRU-Attention粒子群优化门控循环单元融合注意力机制的多变量时间序列预测 目录 多维时序 | MATLAB实现PSO-GRU-Attention粒子群优化门控循环单元融合注意力机制的多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MAT…

python趣味编程-5分钟实现一个谷歌恐龙游戏(含源码、步骤讲解)

Python 恐龙游戏是为想要学习 Python 的初学者创建的。该项目系统使用了 Pygame 和 Random 模块。 Pygame 是一组跨平台的 Python 模块,专为编写视频游戏而设计。 Python 中的 Dino Game有一个任务记录,其中包含图片文档和 Python 内容(dino.py)。 GUI 使用 pygame 库。
最新文章