feat: 工作流程板块支持鼠标拖拽左右滚动

 新增功能:
- 鼠标按住拖拽左右滚动
- 触摸滑动支持(移动端)
- 1.5x 滚动速度
- 防止拖拽时选中文本
- 拖拽时鼠标样式变化(grab → grabbing)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
陈春
2026-06-03 20:22:37 +08:00
parent 3ffc2086e3
commit a6c85c6634
+39 -1
View File
@@ -38,7 +38,18 @@
</svg> </svg>
<!-- 步骤卡片 --> <!-- 步骤卡片 -->
<div class="flex gap-8 md:gap-12 pb-10 overflow-x-auto scrollbar-hide"> <div
ref="cardsContainerRef"
class="flex gap-8 md:gap-12 pb-10 overflow-x-auto scrollbar-hide select-none cursor-grab"
:class="{ 'cursor-grabbing': isDragging }"
@mousedown.prevent="startDrag"
@mousemove="onDrag"
@mouseup="endDrag"
@mouseleave="endDrag"
@touchstart="startDrag"
@touchmove="onDrag"
@touchend="endDrag"
>
<div <div
v-for="(step, index) in steps" v-for="(step, index) in steps"
:key="step.id" :key="step.id"
@@ -112,11 +123,38 @@ const { t } = useI18n()
const rootRef = ref<HTMLElement | null>(null) const rootRef = ref<HTMLElement | null>(null)
const headerRef = ref<HTMLElement | null>(null) const headerRef = ref<HTMLElement | null>(null)
const scrollContainerRef = ref<HTMLElement | null>(null) const scrollContainerRef = ref<HTMLElement | null>(null)
const cardsContainerRef = ref<HTMLElement | null>(null)
const lineRef = ref<SVGElement | null>(null) const lineRef = ref<SVGElement | null>(null)
const linePathRef = ref<SVGPathElement | null>(null) const linePathRef = ref<SVGPathElement | null>(null)
const stepElements = ref<(HTMLElement | null)[]>([]) const stepElements = ref<(HTMLElement | null)[]>([])
let ctx: gsap.Context | null = null let ctx: gsap.Context | null = null
// 拖拽状态
const isDragging = ref(false)
let startX = 0
let scrollLeft = 0
const startDrag = (e: MouseEvent | TouchEvent) => {
if (!cardsContainerRef.value) return
isDragging.value = true
const clientX = 'touches' in e ? e.touches[0].clientX : e.clientX
startX = clientX - cardsContainerRef.value.offsetLeft
scrollLeft = cardsContainerRef.value.scrollLeft
}
const onDrag = (e: MouseEvent | TouchEvent) => {
if (!isDragging.value || !cardsContainerRef.value) return
e.preventDefault()
const clientX = 'touches' in e ? e.touches[0].clientX : e.clientX
const x = clientX - cardsContainerRef.value.offsetLeft
const walk = (x - startX) * 1.5 // 1.5x 速度
cardsContainerRef.value.scrollLeft = scrollLeft - walk
}
const endDrag = () => {
isDragging.value = false
}
const setStepRef = (el: any, index: number) => { const setStepRef = (el: any, index: number) => {
if (el) stepElements.value[index] = el if (el) stepElements.value[index] = el
} }