入门篇跑通了基础功能,但实际监控回放场景还需要:全天录像概览(双进度条)、播放指针居中跟随、点击空白自动续播。这篇文章把这些进阶功能都实现了。
一、双进度条:主时间轴+全天概览

1.1 什么是双进度条?
┌─────────────────────────────────────────┐ ← 主时间轴(可缩放)
│ ████ ████████████ ████████ │
├─────────────────────────────────────────┤ ← 概览条(全天)
│ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │
│ ↑可视窗口 ↑播放位置 │
└─────────────────────────────────────────┘
- 主时间轴:可缩放、可拖动,显示当前视口的细节
- 概览条:显示全天的录像分布,可快速跳转
1.2 启用概览条
vue
<VueTimeAxisPlus
:start-time="startTime"
:segments="segments"
:overview="true"
:overview-height="20"
/>
1.3 运行时动态开关
vue
<template>
<VueTimeAxisPlus ref="timeline" :segments="segments" />
<button @click="$refs.timeline.updateOptions({ overview: true })">显示概览条</button>
<button @click="$refs.timeline.updateOptions({ overview: false })">隐藏概览条</button>
</template>
1.4 概览条点击跳转
点击概览条会触发changeTime事件,可以实现快速跳转:
javascript
onChangeTime(data) {
// 点击概览条时,mode为'click'
// timestamp为点击位置对应的时间
this.seekTo(data.timestamp)
}
二、播放指针居中跟随
2.1 问题
播放时,指针移动到视口边缘就看不到了。
2.2 解决方案
启用centerPointer,播放时自动滚动视口使指针居中:
vue
<VueTimeAxisPlus
ref="timeline"
:center-pointer="true"
@playTime="onPlayTime"
/>
2.3 播放逻辑实现
javascript
data() {
return {
playing: false,
playTimer: null,
playTime: 0
}
},
methods: {
onPlayTime(data) {
// data.timestamp: 当前播放时间
// data.valid: 是否在有效录像内
if (!data.valid) {
// 进入空白区域,查下一段续播
const next = this.$refs.timeline.getNextSegment(data.timestamp)
if (next) {
this.playTime = next.begin
this.$refs.timeline.updateTime(this.playTime)
}
}
},
startPlay() {
this.playing = true
this.playTimer = setInterval(() => {
this.playTime += 1000 // 每秒前进1秒
if (this.playTime >= this.maxTime) {
this.stopPlay()
return
}
this.$refs.timeline.updateTime(this.playTime)
}, 1000)
},
stopPlay() {
this.playing = false
clearInterval(this.playTimer)
}
}
2.4 手势让位后自动恢复
用户拖动时间轴时,播放指针暂停跟随;松手后自动恢复:
vue
<VueTimeAxisPlus
:center-pointer="true"
:center-resume-delay="3000" // 3秒后自动恢复居中
/>
三、跨空白续播
3.1 问题
录像有空白时段(如夜间无录像),用户点击空白区域时怎么处理?
3.2 解决方案
启用snapToNearest,点击空白自动吸附到最近的片段起点:
vue
<VueTimeAxisPlus
:snap-to-nearest="true"
@changeTime="onChangeTime"
/>
3.3 续播逻辑
javascript
onChangeTime(data) {
if (data.mode === 'snap') {
// 被吸附到了下一段起点
console.log(`自动跳转到 ${new Date(data.nextBegin.begin).toLocaleTimeString()}`)
// 开始播放下一段
this.playTime = data.nextBegin.begin
this.startPlay()
}
}
3.4 getNextSegment查询
不依赖snap,手动查询下一段:
javascript
// 从当前时间往后找最近的录像片段
const next = this.$refs.timeline.getNextSegment(this.playTime)
if (next) {
console.log(`下一段: ${new Date(next.begin).toLocaleTimeString()} - ${new Date(next.end).toLocaleTimeString()}`)
console.log(`业务字段: ${next.id}`)
}
3.5 getNextSegments批量查询
获取从当前时间往后的所有片段(可做播放列表):
javascript
const playlist = this.$refs.timeline.getNextSegments(this.playTime)
console.log(`还有 ${playlist.length} 段录像`)
四、自定义样式
4.1 axisStyle配置
vue
<VueTimeAxisPlus
:axis-style="{
borderColor: '#333',
graduationColor: '#666',
tickTextColor: '#fff',
hoverLineColor: '#00ff00',
hoverTextColor: '#00ff00',
overviewBg: '#1a1a1a',
overviewWindowColor: 'rgba(64, 196, 255, 0.2)',
overviewWindowBorder: '#40c4ff',
overviewPlayColor: '#ff5c5c'
}"
/>
4.2 片段样式
每个片段可以独立设置样式:
javascript
segments: [
{
begin: t(6), end: t(7),
style: { background: 'rgba(24,208,217,0.5)' } // 青色
},
{
begin: t(7), end: t(8),
style: { background: 'rgba(255,77,79,0.6)' } // 红色
},
{
begin: t(8), end: t(9),
style: { background: 'rgba(255,165,0,0.5)' } // 橙色
}
]
4.3 主题切换
javascript
const darkTheme = {
tickTextColor: '#ccc',
overviewBg: '#1a1a1a',
overviewWindowColor: 'rgba(64, 196, 255, 0.15)'
}
const lightTheme = {
tickTextColor: '#333',
overviewBg: '#f5f5f5',
overviewWindowColor: 'rgba(64, 196, 255, 0.1)'
}
const switchTheme = (theme) => {
this.$refs.timeline.updateOptions({ axisStyle: theme })
}
五、踩坑记录
坑1:播放指针居中与手势冲突
现象:用户拖动时间轴时,播放指针还在居中跟随,导致视口跳动。
原因:centerPointer和用户手势同时生效。
解决:组件内部已处理,用户手势时自动暂停居中,松手后延迟恢复。
坑2:概览条动态开关后高度不对
现象:运行时切换overview后,时间轴高度没有变化。
原因:没有调用updateOptions。
解决:
javascript
this.$refs.timeline.updateOptions({ overview: true })
// 组件内部会自动重算画布高度
坑3:getNextSegment返回null
现象:调用getNextSegment后返回null。
原因:当前时间已经是最后一段之后。
解决:判断返回值:
javascript
const next = this.$refs.timeline.getNextSegment(time)
if (next) {
// 有下一段
} else {
// 已经是最后一段之后
}
六、总结
| 功能 | 配置 | 关键点 |
|---|---|---|
| 概览条 | overview: true |
支持运行时动态开关 |
| 播放指针居中 | centerPointer: true |
手势时自动暂停 |
| 跨空白续播 | snapToNearest: true |
点击空白自动吸附 |
| 查询下一段 | getNextSegment(time) |
返回完整片段信息 |
| 主题切换 | updateOptions({axisStyle}) |
支持部分字段覆盖 |
更新日期 :2026年9月
调试版本:vue-time-axis-plus 1.x / Vue 3.4+