github完整代码:https://github.com/shuirongshuifu/vue3-echarts5-example
需求描述
- 项目中有视频播放功能
- 采取的是开源组件,西瓜视频的开源组件
- 点击去官网xgplayer
- 大致需求就是若视频没有播放完毕,就不允许拖拽跳着观看
- 当然会有一个字段记录视频有没有播放完毕
关于西瓜视频xgplayer的配置项使用,可以参照笔者之前的文章:https://segmentfault.com/a/1190000044959131
需求实现效果图
两种解决方案
解决方案一
把原本的进度条给删除了,然后使用progress进度条写一个假的,这样的话,就无法做到拖拽了(不过这种方式不太优雅)
解决方案二
- 使用MutationObserver
- 去把进度条dom的pointerEvents属性改为none就行了
- 当用户打开console控制台以后,尝试修改pointerEvents为auto的时候
- MutationObserver会再次把它改为none
- 这样的话,用户就改不了了,就实现了视频不可拖拽功能了
什么是pointerEvents: none
pointerEvents: none
是CSS属性,可以控制元素是否可以响应指针事件(比如如鼠标点击、悬停等)- 换句话说,就是忽略特定元素的交互操作。
- 当我们设置一个元素的
pointer-events
属性为none
时 - 意味着该元素将不会响应任何指针事件。比如点击、拖动和悬停事件
- 大致就是鼠标点击事件(例如
click
)将不会触发 - 鼠标悬停事件(例如
mouseover
和mouseout
)将不会触发。 - 元素上的可拖动操作将被禁用。
- 即通过pointerEvents: none就可以不让用户拖拽这些视频
什么是MutationObserver
- 在这里,笔者不去赘述MutationObserver的语法
- 我们只需要知道,这个api可以实现哪些功能即可
- 想要看具体的语法,请移步至mdn官方:https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObse...
- MutationObserver是一个JavaScript的API,可以监控dom元素的各种变化(炒鸡强大)
- 是2012年被引入的,所以大家可以放心使用,各种浏览器兼容性炒鸡好
- 要是还是不太放心,可以去看can i you上的兼容性列表:https://caniuse.com/?search=MutationObserver
- 所以,当我们给一个dom元素设置了pointerEvents: none;后
- 若有人想要更改,那么MutationObserver可以监控到,然后我们在其回调函数中,再将其修改回来为none
- 这样的话,就相当于无法修改pointerEvents: none;
- 用户就无法拖拽
实际上, MutationObserver 的应用场景非常多,比如强水印无法删除,可以使用这个。用户删除水印dom元素,MutationObserver再创建一个,一样的道理,不赘述
代码方案
先使用xgplayer封装一个MyVideo视频组件
MyVideo.vue文件
<template>
<div id="xgPlayerWrap"></div>
</template>
<script setup>
import { ref, onMounted, reactive, computed } from 'vue';
import Player, { Events } from 'xgplayer'; // 引入西瓜视频模块
import 'xgplayer/dist/index.min.css'; // 引入西瓜视频样式
import { conf } from "./conf"; // 配置文件单独拎出来
defineOptions({ name: 'MyVideo' })
onMounted(() => { init() })
let player = null // 实例
const init = () => {
player = new Player({
...conf
});
player.on(Events.PLAY, (ev) => {
console.log('-播放开始-', ev);
})
player.on(Events.PAUSE, (ev) => {
console.log('-播放结束-', ev);
})
player.on('loadedmetadata', (ev) => {
console.log('-媒体数据加载好了-', ev);
})
player.on(Events.SEEKED, (ev) => {
console.log('-跳着播放-', ev);
})
// 等各种监听事件
}
</script>
conf.js文件
export const conf = {
/**
* 基础功能配置
* */
id: 'xgPlayerWrap', // 占位dom元素
width: 600, height: 400, // 视频宽高尺寸
url: 'https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4', // 视频源
poster: "http://ashuai.work/static/img/avantar.png", // 视频封面
autoplay: false, // 是否自动播放,不自动播放,浏览器有限制规则
autoplayMuted: false, // 是否自动播放(静音播放)
videoInit: true, // 是否默认初始化video,默认初始化,默认true
playsinline: true, // 是否启用内联播放模式,仅移动端生效
defaultPlaybackRate: 1, // 默认播放速度(可选:0.5/0.75/1/1.5/2等)
volume: 0.72, // 播放音量(可选:0 ~ 1)
loop: false, // 是否循环播放,默认不循环播放
startTime: 0, // 点播模式下,初始起播时间
videoAttributes: {}, // video扩展属性,暂且不配置
lang: 'zh-cn', // 播放器初始显示语言,设置为中文
fluid: true, // 是否流式布局(宽高优先于流失布局,默认16:9)注掉上方宽高看效果
fitVideoSize: 'fixed', // 保持容器宽/高,不做适配,按照容器来
videoFillMode: 'auto', // 宽高不够自动底色填充(fill拉伸填充等...)
seekedStatus: 'play', // 跳转后继续播放
// 播放器进度条故事点信息数组
progressDot: [
{
id: 0, // 唯一标识,用于删除的时候索引
time: 30, // 展示的时间点,例子为在播放到10s钟的时候展示
text: '进度条信息提示...', // hover的时候展示文案,可以为空
duration: 5, // 展示时间跨度,单位为s
style: { // 指定样式
backgroundColor: 'pink'
}
},
],
thumbnail: null, // 进度条预览图配置,普通业务用不到
marginControls: false, // 是否开启画面和控制栏分离模式,不开启空间多一些
domEventType: 'default', // 响应的事件类型,不用指定,用默认的即可
/**
* 交互功能配置(一般使用默认即可)
* */
/**
* 插件配置,根据需求自选
* */
icons: {}, // 使用默认的icon图标
i18n: [], // 使用默认的中文
// 自定义一些颜色
commonStyle: {
progressColor: 'green', // 整个进度条颜色
playedColor: 'chocolate', // 已播放的进度条颜色
volumeColor: 'pink', // 音量大小竖向滑块颜色
},
controls: true, // 是否使用底部控制栏,默认使用
miniprogress: true, // 是否使用mini进度条(当底部控制栏隐藏时生效)
screenShot: false, // 关闭截图功能
rotate: true, // 是否使用视频旋转插件,默认不使用
download: true, // 是否使用下载按钮,一般不用,一般自定义控制
pip: true, // 使用使用画中画模式,默认不用
mini: true, // 是否使用小屏幕控件
cssFullscreen: true, // 是否使用网页样式全屏按钮开关
playbackRate: [0.5, 1, 1.5, 2, 3], //传入倍速可选数组
playbackRate: true, //false,禁用倍速播放(即控制栏不显示)
keyShortcut: false, // 是否开启快捷键模式
}
然后在审查一下xgplayer的dom元素结构
- 然后在审查一下xgplayer的dom元素结构
- 看看具体的视频进度条的dom元素是那个,审查后如下图:
- 嗯 是这个dom:
const dom = '#xgPlayerWrap xg-controls xg-inner-controls xg-center-grid xg-progress'
let progressDom = document.querySelector(dom)
- 接下来设置即可:
progressDom.style.pointerEvents = "none"
- 当然,我们还要考虑到,可能会要解除禁止拖拽进度条的需求,即为改成auto接口
progressDom.style.pointerEvents = "auto"
hook代码
// 控制是否禁用xgplayer拖动
export function useCtrlDrag() {
const dom = '#xgPlayerWrap xg-controls xg-inner-controls xg-center-grid xg-progress' // 西瓜视频进度条dom元素
let ob = null // 监控实例
let isFirstRun = true; // 是否初次执行
// 设置不能拖拽
const notDrag = () => {
const progressDom = document.querySelector(dom) // as HTMLElement
if (progressDom) {
progressDom.style.pointerEvents = "none"
}
}
// 设置能拖拽
const canDrag = () => {
const progressDom = document.querySelector(dom) // as HTMLElement
if (progressDom) {
progressDom.style.pointerEvents = "auto"
}
}
// 添加监控不允许拖动
const onMonitor = () => {
// 先重置一下
offMonitor()
notDrag()
// 再做监控
ob = new MutationObserver((records) => {
// 初始执行不监控
if (isFirstRun) {
isFirstRun = false;
return;
}
for (const record of records) {
// 删除不用管,只监控修改
if (record.target instanceof HTMLElement && record.target.tagName === "XG-PROGRESS") {
console.log('修改了');
notDrag()
}
}
});
// 监控实例,监控进度条元素,在加上对应配置项
const progressDom = document.querySelector(dom) // as HTMLElement
ob.observe(progressDom, {
childList: true, // 监控所有子元素
attributes: true, // 监控属性是否发生变化
subtree: false, // 子树监控
});
}
// 移除监控,允许拖动
const offMonitor = () => {
if (ob) {
ob.disconnect() // 结束
ob = null // 置为空
}
canDrag()
}
return { onMonitor, offMonitor }
}
然后把hook应用到刚刚封装的MyVideo组件上去
<template>
<div id="xgPlayerWrap"></div>
</template>
<script setup>
import Player, { Events } from 'xgplayer'; // 引入西瓜视频模块
import 'xgplayer/dist/index.min.css'; // 引入西瓜视频样式
import { conf } from "./conf"; // 配置文件单独拎出来
// 引入hook
import { useCtrlDrag } from "@/hook/ctrlDrag";
const { onMonitor, offMonitor } = useCtrlDrag()
// 定义参数,是否可以拖拽视频
const props = defineProps({
disabledDrag: {
type: Boolean,
default: false
}
})
onMounted(() => { init() })
let player = null // 实例
const init = () => {
player = new Player({
...conf
});
// 控制是否禁用拖拽
props.disabledDrag ? onMonitor() : offMonitor()
player.on(Events.PLAY, (ev) => {
console.log('-播放开始-', ev);
})
...
}
</script>
组件上布尔值控制是否可拖拽
<template>
<div class="out">
<h1>不可拖拽</h1>
<MyVideo :disabledDrag="disabledDrag" />
<br>
<br>
<el-switch v-model="disabledDrag" active-text="开启禁止拖拽功能" inactive-text="关闭禁止拖拽功能" />
</div>
</template>
<script setup>
import { ref } from "vue";
import MyVideo from "../../components/MyVideo/MyVideo.vue";
const disabledDrag = ref(true)
</script>
至此,搞定...
此外,一键提交git代码的bat脚本
- 笔者自己写一个小项目
- 每次还得add commit填写内容
- 倒是有些麻烦了
- 干脆写一个bat命令行脚本
- 双击一键提交代码,快速简洁方便
- bat放在和.git文件夹同级目录下即可
- 如下:
auto.bat
@echo off
git add .
git commit -m "Auto commit"
git pull
git push
pause
这种方式仅适用于自己写demo代码提交,团队开发不太适用,当然也可以添加交互的bat命令行,再此不赘述,大家可自由探索
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。