vue-time-axis-plus进阶:双进度条+跨空白续播+播放指针,打造专业级监控回放体验

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


一、双进度条:主时间轴+全天概览

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+

相关推荐
mmsx1 小时前
MapLibre 实战 09|Bug 单写着"地图被风刮走了":一个瓦片源工厂,是三个线上事故换来的
android·前端·开源
不羁的木木1 小时前
给鸿蒙 App 增加打开外部网页能力 —— flutter_web_browser 的鸿蒙使用指南
前端·flutter·harmonyos
广州山泉婚姻1 小时前
微服务时代,前后端分离架构该怎样高效协同?
前端·后端
EatFan1 小时前
多租户系统到底怎么设计?从 tenant_id 到 JWT 租户隔离的真实实践
前端·后端·全栈·多租户
计算机魔术师1 小时前
硅谷四大AI巨头联手踩刹车,是真心怕失控还是怕被超越?
前端
岁岁种桃花儿1 小时前
Vue组件第六篇:Vue单文件组件
开发语言·前端·javascript·vue.js
yivifu1 小时前
创建支持交叉链接且鼠标悬停显示注释框的HTML文件
前端·javascript·html
GreenTea2 小时前
🔥别再用压缩了,Codex、NVIDIA、DeepSeek、Uber 给出 Agent 上下文管理的新答案
前端·后端·算法
IT_陈寒2 小时前
React重渲染这坑,我跳进去又爬出来了
前端·人工智能·后端