一个Vue视频媒体多段裁剪组件的实现示例

近日项目有个新需求,需要对视频或音频进行多段裁剪然后拼接。例如,一段视频长30分钟,我需要将5-10分钟、17-22分钟、24-29分钟这三段拼接到一起成一整段视频。裁剪在前端,拼接在后端。

网上简单找了找,基本都是客户端内的工具,没有纯网页的裁剪。既然没有,那就动手写一个。

代码已上传到GitHub: https://github.com/fengma1992/media-cut-tool

废话不多,下面就来看看怎么设计的。

效果图

一个Vue视频媒体多段裁剪组件的实现示例

图中底部的功能块为裁剪工具组件,上方的视频为演示用,当然也能是音频。

功能特点:

支持鼠标拖拽输入与键盘数字输入两种模式;

支持预览播放指定裁剪片段;

左侧鼠标输入与右侧键盘输入联动;

鼠标移动时自动捕捉高亮拖拽条;

确认裁剪时自动去重;

*注:项目中的图标都替换成了文字

思路

整体来看,通过一个数据数组 cropItemList 来保存用户输入数据,不管是鼠标拖拽还是键盘输入,都来操作 cropItemList 实现两侧数据联动。最后通过处理 cropItemList 来输出用户想要的裁剪。

cropItemList 结构如下:

cropItemList: [ { startTime: 0, // 开始时间 endTime: 100, // 结束时间 startTimeArr: [hoursStr, minutesStr, secondsStr], // 时分秒字符串 endTimeArr: [hoursStr, minutesStr, secondsStr], // 时分秒字符串 startTimeIndicatorOffsetX: 0, // 开始时间在左侧拖动区X偏移量 endTimeIndicatorOffsetX: 100, // 结束时间在左侧拖动区X偏移量 } ]

第一步

既然是多段裁剪,那么用户得知道裁剪了哪些时间段,这通过右侧的裁剪列表来呈现。

列表

列表存在三个状态:

无数据状态

无数据的时候显示内容为空,当用户点击输入框时主动为他生成一条数据,默认为视频长度的1/4到3/4处。

有一条数据

此时界面显示很简单,将唯一一条数据呈现。

有多条数据

一个Vue视频媒体多段裁剪组件的实现示例

有多条数据时就得有额外处理了,因为第1条数据在最下方,而如果用 v-for 去循环 cropItemList,那么就会出现下图的状况:

一个Vue视频媒体多段裁剪组件的实现示例

而且,第1条最右侧是添加按钮,而剩下的最右侧都是删除按钮。所以,我们 将第1条单独提出来写,然后将 cropItemList 逆序生成一个 renderList 并循环 renderList 的 0 -> listLength - 2 条

即可。

<template v-for="(item, index) in renderList"> <div v-if="index < listLength -1" :key="index"> ... ... </div> </template>

下图为最终效果:

一个Vue视频媒体多段裁剪组件的实现示例

时分秒输入

这个其实就是写三个 input 框,设 type="text" (设成 type=number 输入框右侧会有上下箭头),然后通过监听input事件来保证输入的正确性并更新数据。监听focus事件来确定是否需要在 cropItemList 为空时主动添加一条数据。

<div> <input type="text" :value="renderList[listLength -1] && renderList[listLength -1].startTimeArr[0]" @input="startTimeChange($event, 0, 0)" @focus="inputFocus()"/> : <input type="text" :value="renderList[listLength -1] && renderList[listLength -1].startTimeArr[1]" @input="startTimeChange($event, 0, 1)" @focus="inputFocus()"/> : <input type="text" :value="renderList[listLength -1] && renderList[listLength -1].startTimeArr[2]" @input="startTimeChange($event, 0, 2)" @focus="inputFocus()"/> </div>

播放片段

点击播放按钮时会通过 playingItem 记录当前播放的片段,然后向上层发出 play 事件并带上播放起始时间。同样还有 pause 和 stop 事件,来控制媒体暂停与停止。

<CropTool :duration="duration" :playing="playing" :currentPlayingTime="currentTime" @play="playVideo" @pause="pauseVideo" @stop="stopVideo"/>

/** * 播放选中片段 * @param index */ playSelectedClip: function (index) { if (!this.listLength) { console.log('无裁剪片段') return } this.playingItem = this.cropItemList[index] this.playingIndex = index this.isCropping = false this.$emit('play', this.playingItem.startTime || 0) }

这里控制了开始播放,那么如何让媒体播到裁剪结束时间的时候自动停止呢?

监听媒体的 timeupdate 事件并实时对比媒体的 currentTime 与 playingItem 的 endTime ,达到的时候就发出 pause 事件通知媒体暂停。

if (currentTime >= playingItem.endTime) { this.pause() }

至此,键盘输入的裁剪列表基本完成,下面介绍鼠标拖拽输入。

第二步

下面介绍如何通过鼠标点击与拖拽输入。

1、确定鼠标交互逻辑

新增裁剪

鼠标在拖拽区点击后,新增一条裁剪数据,开始时间与结束时间均为 mouseup 时进度条的时间,并让结束时间戳跟随鼠标移动,进入编辑状态。

确认时间戳

编辑状态,鼠标移动时,时间戳根据鼠标在进度条的当前位置来随动,鼠标再次点击后确认当前时间,并终止时间戳跟随鼠标移动。

更改时间

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/276a2b4016bf0459a220b5ad84eaa1a9.html