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是一个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命令行,再此不赘述,大家可自由探索

水冗水孚
1.1k 声望584 粉丝

每一个不曾起舞的日子,都是对生命的辜负