feat: 工作流程板块支持鼠标拖拽左右滚动
✨ 新增功能: - 鼠标按住拖拽左右滚动 - 触摸滑动支持(移动端) - 1.5x 滚动速度 - 防止拖拽时选中文本 - 拖拽时鼠标样式变化(grab → grabbing) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user