使用video组件自己的全屏功能时,浏览器将自动全屏video组件。
而video.js插件二次开发他全屏的是组件外部的div,加入水印逻辑就是在获取player.el节点之后插入div元素实现水印功能。
1.引入video.js插件
javascript
npm i video.js -S
2.页面引入video.js插件以及样式
import videojs from "video.js";
import "video.js/dist/video-js.css";
3.开发一个video.js Plugins插件 Watemark.js
import videojs from 'video.js';
import moment from 'moment'
// Default options for the plugin.
const defaults = {
position: 'top-right',
fadeTime: 3000,
url: undefined,
image: undefined
};
/**
* 移除已存在的水印元素
*
* @function removeExistingWatermark
* @param {HTMLElement} container
*/
const removeExistingWatermark = (container) => {
const existingWatermark = container.querySelector('.vjs-watermark-content');
if (existingWatermark) {
existingWatermark.remove();
}
};
/**
* Sets up the div, img and optional a tags for the plugin.
*
* @function setupWatermark
* @param {Player} player
* @param {Object} [options={}]
*/
const setupWatermark = (player, options) => {
// Add a div and img tag
const videoEl = player.el();
if (!videoEl) return;
const container = videoEl;
// 先移除已存在的水印,避免重复创建
removeExistingWatermark(container);
// 水印尺寸估计(用于确保水印完全在容器内)
const watermarkWidth = 300;
const watermarkHeight = 32;
// 计算随机位置,确保水印完全在容器内
const maxX = container.clientWidth - watermarkWidth;
const maxY = container.clientHeight - watermarkHeight;
const randomX = Math.floor(Math.random() * maxX);
const randomY = Math.floor(Math.random() * maxY);
const div = document.createElement('div');
div.classList.add('vjs-watermark-content');
Object.assign(div.style, {
position: 'absolute',
top: `${maxY - 50}px`,
left: `${50}px`,
color: '#000',
fontSize: '16px',
pointerEvents: 'none', // 不影响操作
whiteSpace: 'nowrap',
userSelect: 'none',
zIndex: 99,
fontWeight: 'bold',
opacity: 0.12
})
div.textContent = options.text;
const p = document.createElement('p');
p.textContent = moment().format('YYYY-MM-DD HH:mm')
div.appendChild(p);
videoEl.appendChild(div);
};
/**
* Fades the watermark image.
*
* @function fadeWatermark
* @param {Object} [options={
* fadeTime:
* 'The number of milliseconds before the inital watermark fade out'}]
*/
const fadeWatermark = (options) => {
setTimeout(
() => document.getElementsByClassName('vjs-watermark-content')[0]
.classList.add('vjs-watermark-fade'),
options.fadeTime
);
};
/**
* Function to invoke when the player is ready.
*
* This is a great place for your plugin to initialize itself. When this
* function is called, the player will have its DOM and child components
* in place.
*
* @function onPlayerReady
* @param {Player} player
* @param {Object} [options={}]
*/
const onPlayerReady = (player, options) => {
player.addClass('vjs-watermark');
// if there is no image set just exit
if (!options.text) {
return;
}
setupWatermark(player, options);
// Setup watermark autofade
if (options.fadeTime === null) {
return;
}
player.on('play', () => fadeWatermark(options));
player.on('fullscreenchange', () => {
// 全屏变化时更新水印,setupWatermark函数内部已处理移除旧水印
setupWatermark(player, options);
});
// 确保在组件卸载时清理水印
player.on('dispose', () => {
const videoEl = player.el();
if (videoEl) {
removeExistingWatermark(videoEl);
}
});
};
/**
* A video.js plugin.
*
* In the plugin function, the value of `this` is a video.js `Player`
* instance. You cannot rely on the player being in a "ready" state here,
* depending on how the plugin is invoked. This may or may not be important
* to you; if not, remove the wait for "ready"!
*
* @function watermark
* @param {Object} [options={}]
* An object of options left to the plugin author to define.
*/
const watermark = function (options) {
this.ready(() => {
onPlayerReady(this, videojs.mergeOptions(defaults, options));
});
};
// Register the plugin with video.js.
videojs.registerPlugin('watermark', watermark);
// Include the version number.
watermark.VERSION = '__VERSION__';
export default watermark;
记得引入
import "./watemark.js";
4.调用videojs加载watermark代码
var player = videojs(
playerRef.current,
{
plugins: {
watermark: {
text: "www.jz07.cn",
opacity: 0.5
}
},
height: height,
width: width,
autoplay: false, //是否自动播放
loop: false, //是否循环播放
controls: true, //控制器
controlBar: {
// 设置控制条组件
playbackRateMenuButton: true
}
}, () => {
onReady?.()
});