Vue + 原生JS + 原生CSS3 实现视频时间点在时间轴上的动态可视化

12 篇文章 0 订阅
7 篇文章 0 订阅

需求

  1. 根据关键字在视频中的出现时间,在模拟的视频时间轴中显示对应的位置
  2. 用户点击,选择不同的关键字,显示对应关键词时间
  3. 点击进度条中的关键词时间点,视频对应跳转到该时间播放

实现效果

videoKey

模拟后台数据

针对这个需求模拟后台发来的数据,每个关键词分别有value内容以及time数组,包括该关键词在视频中出现的所有时间点,在页面中展示的也应为对应每个关键词的时间点在时间轴上的可视化。

videoAnalysis: {
    //关键词
    key: [
        {
            value: "学习", 
            time: [
                '00:00:01',
                '00:05:52',
                '00:01:12',
                '00:02:32'
            ]
        },
        {
            value: "2018",
            time: [
                '00:02:02',
                '00:03:52',
                '00:07:12',
                '00:04:52',
                '00:04:12',
                '00:06:32',
                '00:01:32'
            ]
        },
        //...
    ],

实现方法

数据结构

//数据结构
data: {
    keyStatus: [],
    keyX:[],//关键词时间坐标
    videoTotalTime: '00:10:00', //视频总时长
}
  1. keyStatus是一个一维对象数组,储存每个关键词的显隐布尔值{status: false}。若用户点击,则对应index值为true,其他为false

  2. keyX是一个二维数组,储存每个关键词对应的所有时间点的坐标,利用:style来动态控制每个时间点在时间轴上的横坐标

html

<!--关键词显示-->
<div id="keyContent" 
    class="keyContent1" 
    v-for="(item,index) of videoAnalysis.key" 
    :key="index" 
    @click= "changeKey(index)">
            {{item.value}}
</div>

<!--时间点可视化-->
<div class="progressbar">
    <div v-for="(item,_index) of videoAnalysis.key" :key="_index">
        <div v-show="keyStatus[_index].status" 
            class="keyItemBox" 
            v-for="(item, __index) of videoAnalysis.key[_index].time" 
            :key="__index"
            :style="getStyle(_index, __index)"
            @click="changeVideoTime(item)"
        >
        </div>
    </div>
</div>

这里的重点有三个:

  1. v-forv-show的嵌套循环

    • 外层的v-for循环所有关键词 -> v-for="(item,_index) of videoAnalysis.key"
    • 内层的v-for循环对应关键词的每个时间点 -> v-for="(item, __index) of videoAnalysis.key[_index].time"
  2. v-show来控制每个关键点时间的显示 -> v-show="keyStatus[_index].status"

    1. 为什么不用v-if?
      v-showv-if在功能上都能控制元素的显隐,但实现原理不一样。

      • v-if是动态的向DOM树内添加或者删除DOM元素;
      • 而v-show是听过设置DOM元素的display属性来控制元素的显示

      因此v-if切换时有一个个局部编译/卸载的过程,而v-show只是简单的基于css的切换,所以针对这种需要频繁切换的需求,若v-if会有更高的切换消耗

    2. keyStatus[_index].status代表着什么?
      keyStatus[_index].status精确到每个关键词,对应的status为用户当 前点击的关键词,即为页面上应该显示的关键词时间轴。

  3. 使用:style="getStyle(_index, __index)"来对时间轴上的每个时间点进行定位
    因为针对每个关键词出现的所有时间点都要在时间轴上进行定位,所以需要针对不同的时间点来动态设定其相对时间轴的X坐标

JS功能实现

初始化
beforeMount() {
    //计算视频总时长
    var videoTotalTime = this.videoTotalTime.split(":");
    var videototaltime = 3600 * parseInt(videoTotalTime[0]) + 60 * parseInt(videoTotalTime[1]) + parseInt(videoTotalTime[2]);

    var key = this.videoAnalysis.key
    //var obj = { status: false }
    for (var i = 0; i < key.length; i++) {
        
        this.keyStatus.push({ status: false}) //给每一个关键词初始化为false
        //console.log(this.keyStatus)

        var width = 500 //视频进度条像素宽度
        var time = key[i].time
        var array = []
        for (var j = 0; j < time.length; j++) {
            var keyTime = time[j].split(":");
            var keytime = 3600 * parseInt(keyTime[0]) + 60 * parseInt(keyTime[1]) + parseInt(keyTime[2]);
            var bi = keytime / videototaltime //时间占总时间的比例
            var x = bi * width //位置
            array.push(x.toFixed(2)) //保留两位小数
            this.keyX[i] = array //二维数组
        }
    }
    this.keyStatus[0].status = true //默认显示第一个关键词的时间轴
}

具体实现方法都在注释里了,这里有一个问题,即为被注释掉的//var obj = { status: false },为何不能在这里通过定义obj再将其push进keyStatus呢。

这是因为obj是在循坏外的,若在循环内将其push进数组,每次push进的为同一个obj,即指针指向的是同一个对象,会使后期代码出现问题。

点击切换关键词
changeKey (index) {
    for(var i = 0; i < this.keyStatus.length; i++) {
        this.keyStatus[i].status = false
    }
    this.keyStatus[index].status = true
    //console.log(this.keyStatus)
},

切换关键词是应该先将所有值赋为false,再将用户点击的当前关键词赋为true来实现关键词的更新

实现时间点可视化
getStyle(_index, __index) {
    var value = this.keyX[_index][__index]
    //console.log(value)
    return  'transform: translateX(' + value + 'px)';
    //利用translateX实现X坐标的移动
}

//改变视频播放
changeVideoTime(time) {
    var timeSecond = time.split(":");
    var totalTime = 3600 * parseInt(timeSecond[0]) + 60 * parseInt(timeSecond[1]) + parseInt(timeSecond[2]);
    var thisVideo = document.getElementById("video");
    thisVideo.currentTime = totalTime;
},

遇到的问题

v-show 用布尔类型的数组绑定无法监听

刚开始,因为keyStatus这个数组只需储存关键词的布尔值,所以将其设为布尔类型的数组,但是发现无法成功渲染。
应该使用对象{satatus:falase},通过键值对来进行监听

生命周期造成的对象undefined问题

刚开始将初始化写在函数mounted里,发现浏览器报错

videoKeyError

查询了一下资料,发现这是因为页面渲染刚的时候还没有拿到这个值,所以会报错。那如果写在beforeMount里呢?试验了一下,发现报错消失

总结

之前没有写过类似的需求,在网上找了一下也没有找到类似的库与方法,所以自己用原生JS和CSS写了一个,性能肯定是不够好的,后续会继续优化,看到这篇博客的前端小伙伴可以多多交流,提意见就更好啦

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值