优化时间线组件

- 更新时间轴操作说明
- 解决播放头在移动时的粗细变化
- 解决快速拖动播放头,松开鼠标后的播放头闪现
This commit is contained in:
yueliuli 2026-04-24 11:46:23 +08:00
parent e26be2cb89
commit 8cd8045649
3 changed files with 33 additions and 13 deletions

View File

@ -98,9 +98,19 @@
top: 0;
bottom: 0;
width: 2px;
background-color: #ef4444;
z-index: 25;
cursor: ew-resize;
transform: translateZ(0);
}
.playhead::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 2px;
height: 100%;
background-color: #ef4444;
}
.playhead-indicator {

View File

@ -64,6 +64,7 @@ export function useTimeline(
const isPlayheadDragging = ref(false)
const isRulerDragging = ref(false)
const isMounted = ref(false)
const displayFrame = ref(0)
const dragStartX = ref(0)
const scrollStartLeft = ref(0)
const localCurrentFrame = ref(0)
@ -121,18 +122,16 @@ export function useTimeline(
// 计算缩放前后的位置偏移
// console.log('container.scrollLeft', container.scrollLeft)
if (playheadVisible) {
// 以播放头为中心缩放
const playheadX = playheadPosition - containerScrollLeft
const newPlayheadPosition = props.currentFrame * newPxPerFrame
const newScrollLeft = newPlayheadPosition - playheadX
const newScrollLeft = Math.round(newPlayheadPosition - playheadX)
container.scrollLeft = newScrollLeft
}
else {
// 以容器中心为中心缩放
const centerX = containerWidth / 2
const centerPosition = containerScrollLeft + centerX
const newCenterPosition = centerPosition * (newPxPerFrame / oldPxPerFrame)
container.scrollLeft = newCenterPosition - centerX
container.scrollLeft = Math.round(newCenterPosition - centerX)
}
// 最后更新缩放值
@ -175,9 +174,7 @@ export function useTimeline(
}
const playheadPos: ComputedRef<number> = computed(() => {
const frame = isPlayheadDragging.value ? localCurrentFrame.value : props.currentFrame
const clampedFrame = Math.max(0, Math.min(frame, props.totalFrames - 1))
return clampedFrame * pxPerFrame.value
return Math.round(displayFrame.value * pxPerFrame.value)
})
const trackRows: ComputedRef<HazardRow[][]> = computed(() => {
@ -260,6 +257,15 @@ export function useTimeline(
if (!timelineContainer.value)
return
e.preventDefault()
if (e.shiftKey) {
const delta = e.deltaY || e.deltaX
const zoomDelta = delta > 0 ? -0.1 : 0.1
const newZoom = pxPerFrame.value + zoomDelta
setZoom(newZoom)
return
}
const container = timelineContainer.value
const delta = e.deltaY || e.deltaX
container.scrollLeft += delta
@ -318,6 +324,7 @@ export function useTimeline(
const frame = Math.floor(x / pxPerFrame.value)
const clampedFrame = Math.max(0, Math.min(frame, props.totalFrames - 1))
localCurrentFrame.value = clampedFrame
displayFrame.value = clampedFrame
emit('frameChange', clampedFrame)
}
@ -330,13 +337,16 @@ export function useTimeline(
const frame = Math.floor(x / pxPerFrame.value)
const clampedFrame = Math.max(0, Math.min(frame, props.totalFrames - 1))
localCurrentFrame.value = clampedFrame
displayFrame.value = clampedFrame
emit('frameChange', clampedFrame)
}
watch(() => props.currentFrame, () => {
if (!isPlayheadDragging.value) {
localCurrentFrame.value = props.currentFrame
}
if (isPlayheadDragging.value)
return
displayFrame.value = props.currentFrame
nextTick(() => {
if (!timelineContainer.value)
return
@ -408,7 +418,7 @@ export function useTimeline(
isDragging,
isPlayheadDragging,
isRulerDragging,
localCurrentFrame,
displayFrame,
trackWidth,
timeTicks,
secondTicks,

View File

@ -50,7 +50,7 @@ onUnmounted(() => {
<el-button
type="info" dashed :icon="InfoFilled" size="small"
@click="openMessageBox(
'拖动播放头控制播放进度。滚轮/拖动时间轴前后移动。点击隐患编号跳转对应隐患。',
'拖动播放头 控制播放进度。滚轮/拖动 时间轴前后移动。点击隐患编号跳转对应隐患。shift键+鼠标滚轮 缩放时间轴。',
'操作说明',
)"
>