一、前置信息
本文记录使用 uniapp内置组件slider ➕ video-player 实现自定义进度条
-
功能描述:用户可通过拖动,或点击进度某点实现使视频播放到指定进度,在拖动中时间不会动态更新,只在拖动完毕以后更新
-
成品图
-
需要用到的事件如下:
<video-player>
-
@timeupdate : 播放进度变化时触发,返回当前播放时间点及视频总时长,单位:秒(s)。event.detail = { currentTime, duration }
-
@seekcomplete : seek 完成时触发。返回 seek 完成后的播放时间点,单位:秒(s)。event.detail={position}。
-
<slider>
-
@change : 完成一次拖动后触发的事件,event.detail = {value: value}
-
@changing : 拖动过程中触发的事件,event.detail = {value: value}
-
-
其他:
-
本次没有使用原生引用
<video-player>
组件,只是在pages.json中加入了,"usingComponents": { "video-player":"ext://industry/video-player" }
-
参考上条,
"disableSwipeBack": true
禁止左滑属性没有生效
-
二、正文
- html主要结构如下:
- 注意: 此处没写到
<swiper>
外面,因为属性禁止左滑没生效,写在外面在滑动过程中总是触发左滑返回,写在此处可正常拖动
- 注意: 此处没写到
<swiper>
<swiper-item>
// video-player 组件参数仅展示本次所需
<video-player
...
id="myVideo"
...
@timeupdate="Addtimeupdate"
...
/>
// 下面是自定义的进度条(.stop 防冒泡)
// .barview 样式把进度条定到页面底部
<view class="barview">
<text>{{ currentTimeText }}</text>
<slider
:value="progressPercent"
:min="0"
:max="100"
:blockSize="20"
backgroundColor="#fff"
@change.stop="sliderChange"
@changing.stop="this.isDrag=true"
>
</slider>
<text>{{ totalTimeText }}</text>
</view>
</swiper-item>
</swiper>
- js代码
<script>
export default{
data(){
return{
isPlaying: false, // 视频播放标识 true 正在播放 false 暂停播放
//进度条相关
isDrag: false, // //进度条是否在拖拽
progressPercent: 0, // 进度条百分比
videoDuration: 0, // 视频总时长(以秒为单位)
currentTime: 0, // 当前视频播放进度(以秒为单位,没用可以不要)
currentTimeText: "00:00", // 进度条左侧-当前播放时间
totalTimeText: "00:00", // 进度条右侧-总时长
}
},
methods:{
/**播放进度变化时触发,动态给进度条赋值 */
Addtimeupdate(event) {
// 如果进度条正在拖动,则停止在页面同步当前播放进度
if (this.isDrag) return;
const totalDuration = event.detail.duration ? event.detail.duration : this.videoDuration
// 记录当前集的总时间(以秒为单位)
this.videoDuration = totalDuration;
// 获取总时长(去小数)
this.totalTimeText = this.formatTime(totalDuration);
const activeDuration = event.detail.currentTime || event.target.currentTime;
// 记录当前时间(以秒为单位)
this.currentTime = activeDuration
// 设置当前时长(去小数)
this.currentTimeText = this.formatTime(activeDuration);
// 获取自定义进度条的当前进度值
this.progressPercent = (activeDuration / totalDuration) * 100;
},
/** 本方法用于把秒转换为 mm:ss 的格式 */
formatTime(seconds) {
const minutes = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${minutes}:${secs < 10 ? "0" : ""}${secs}`;
},
/** 拖拽结束时触发 */
sliderChange(e) {
const video = uni.createVideoContext("myVideo", this);
if (!video) return;
// 暂停视频
video.pause()
if(e.detail.value == 100){
this.isDrag = false;
// 如果直接拖动到结尾,直接调用视频播放结束事件,不必再跳转到指定时间
this.videoEnded()
return
}
// 避免用户直接点击进度条,触发不了changing事件(ios部分机型复现)
this.isDrag = true;
// 跳到指定时间点
video.seek((e.detail.value / 100) * this.videoDuration);
},
/** 视频seek完成触发的回调 */
seekcomplete(e){
// 避免ios在切页面再回来时(部分机型偶现),自动触发本事件,导致bug
if(this.isDrag){
this.isDrag = false;
// seek完判断视频状态
if(this.isPlaying){
// 如果是播放状态就恢复播放
const video = uni.createVideoContext("myVideo", this);
if (!video) return;
// 播放视频
video.play()
}else{
// 暂停情况下,拖动完手动更新进度条时间
// (自己模拟了event结构)
const myCurrentE = {
detail: {
currentTime: e.detail.position
}
}
this.Addtimeupdate(myCurrentE)
}
}
},
}
}
</script>
划重点:
-
为什么要在 @change 中先暂停,再在 @seekcomplete 中播放?
-
模拟情况:在 @change 中暂停,seek完,再播放
-
bug:进度条闪烁,暂停完, @timeupdate 会被再偶现触发一次或n次,导致进度条频闪
-
-
@change 已经把 isDrag 改为 true 了,为什么在 @change 中还要再改一次?
- 避免用户直接点击进度条,触发不了 @changing 事件(ios部分机型复现)
-
拖到100的时候不可以让他自己播放到结束吗?
- 不可以,会bug(具体记不清了)
结语
—————— 写完啦,感谢观看 ( ̄︶ ̄*)),欢迎指正 ——————