目录
参考网址
效果图,暂停时显示暂停图标,播放时隐藏暂停图标
代码说明,代码传入url后,可直接复制使用
VideoPausedIcon.ts 组件
VideoCom.tsx
Video.module.less
在Video.js播放器中定制自己的组件 - acgtofe
注意:videojs升级后,不能用extend创建组件,需要按下方代码建一个组件
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();
}
}
}
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 = (props: any) => {
const videoRef = React.useRef(null);
const playerRef = React.useRef(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 (
);
};
export default VideoCom;
.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);
}
}
}
}
}
}