基于Vue3+TypeScript实现抖音式卡片滑动交互功能

 更新时间:2026年06月03日 09:00:43   作者:龙虾不加班  
本文介绍如何用 Vue 3 + TypeScript 实现类似抖音的卡片滑动交互,应用于单词记忆场景,完整方案包含手势识别、堆叠动画、实时反馈和状态管理,需要的朋友可以参考下

效果拆解

目标效果:屏幕中央一张主卡片,后方隐约可见两张堆叠卡片。手指左滑(不认识)或右滑(认识),卡片跟随手指移动并旋转,松开后飞出屏幕,下一张顶上。

核心需求:

  • 3 张可见卡片(z-index 分层,缩放递减)
  • Pointer Events 手势跟踪
  • 滑动过程实时视觉反馈(颜色、图标、标签)
  • 阈值判断 + 飞出动画 + 队列循环

卡片堆叠布局

三张卡片用 v-for 渲染,通过 index 控制层级和变形:

const stackStyle = (stackIndex: number) => {
  if (stackIndex >= 3) return { display: 'none' }

  const scaleMap = [1, 0.95, 0.90]      // 越靠后越小
  const yOffsetMap = [0, 12, 24]         // 越靠后越向下
  const zIndexMap = [30, 29, 28]         // 越靠前越高

  return {
    zIndex: zIndexMap[stackIndex],
    transform: `scale(${scaleMap[stackIndex]}) translateY(${yOffsetMap[stackIndex]}px)`,
    transition: stackIndex === 0 && isDragging.value
      ? 'none'                           // 拖拽中不要过渡
      : 'transform 0.35s ease'
  }
}

数组用 ref<Word[]>([]) 存储当前队列。队列用完时自动从后端拉取下一批。

Pointer Events 手势跟踪

用 Pointer Events 而非 Touch Events,因为 Pointer Events 同时支持触屏和鼠标,方便开发调试:

const SWIPE_THRESHOLD = 72  // px,超过此值触发飞出
const isDragging = ref(false)
const dragX = ref(0)

const onPointerDown = (e: PointerEvent) => {
  isDragging.value = true
  startX.value = e.clientX
  ;(e.target as HTMLElement).setPointerCapture(e.pointerId)
}

const onPointerMove = (e: PointerEvent) => {
  if (!isDragging.value) return
  dragX.value = e.clientX - startX.value
}

const onPointerUp = () => {
  if (!isDragging.value) return
  isDragging.value = false

  if (Math.abs(dragX.value) > SWIPE_THRESHOLD) {
    // 触发飞出
    const direction = dragX.value > 0 ? 'right' : 'left'
    flyAway(direction)
  } else {
    // 复位
    dragX.value = 0
  }
}

关键点:setPointerCapture 确保手指滑出元素边界后依然能跟踪。不用这个 API 的话,手指移出卡片范围就会丢失 tracking。

实时视觉反馈

根据拖拽距离动态计算颜色和图标透明度:

const feedbackColor = computed(() => {
  const ratio = Math.min(Math.abs(dragX.value) / SWIPE_THRESHOLD, 1)
  if (dragX.value > 0) {
    return `rgba(34, 197, 94, ${ratio * 0.3})`  // 绿色 = 认识
  } else if (dragX.value < 0) {
    return `rgba(239, 68, 68, ${ratio * 0.3})`  // 红色 = 不认识
  }
  return 'transparent'
})

const checkIconOpacity = computed(() =>
  dragX.value > 0 ? Math.min(dragX.value / SWIPE_THRESHOLD, 1) : 0
)

const crossIconOpacity = computed(() =>
  dragX.value < 0 ? Math.min(-dragX.value / SWIPE_THRESHOLD, 1) : 0
)

拖拽距离与阈值的比值驱动所有视觉过渡。不需要动画库,computed 全搞定。

飞出动画 + 队列推进

飞出用 CSS transition + 最终位置计算:

const flyAway = (direction: 'left' | 'right') => {
  const targetX = direction === 'right' ? window.innerWidth * 1.5 : -window.innerWidth * 1.5
  flyX.value = targetX
  flyRotation.value = direction === 'right' ? 20 : -20

  // 记录结果
  const result = direction === 'right' ? 'known' : 'forgotten'
  submitReview(currentWord.value.id, result)

  // 动画结束后移除当前词,推进队列
  setTimeout(() => {
    words.value.shift()
    flyX.value = 0
    flyRotation.value = 0
    dragX.value = 0
    // 队列快用完时预加载
    if (words.value.length < 5) fetchMoreWords()
  }, 350)
}

飞出期间新卡片已经在原来的第二张位置就位,视觉上无缝衔接。

四队列切换

高频词、大纲词、综合、错词巩固,四种模式对应不同 API 参数:

type QueueMode = 'high' | 'outline' | 'mixed' | 'wrong'

const switchQueue = async (mode: QueueMode) => {
  currentMode.value = mode
  words.value = []
  await fetchWords(mode)
}

错词队列的每个词带有复习记录,后端根据复习次数和上次复习时间动态计算下次推送时机,实现间隔重复。

性能注意事项

  • 事件监听用 passive: false:Pointer Events 需要 preventDefault 防止页面滚动,所以要显式设置 { passive: false }
  • 动画用 transform 而非 left/top:transform 走合成层,不触发重排
  • 队列预加载:剩 5 张时自动拉取,滑动体验零等待

完整代码较长,核心逻辑即上面这些。这个交互方案可以直接复用到任何需要卡片滑动判断的场景——背单词、刷题、审阅、相亲……

在线体验:m.dobell.top,打开就能看到效果。

以上就是基于Vue3+TypeScript实现抖音式卡片滑动交互功能的详细内容,更多关于Vue3 TypeScript抖音式卡片滑动交互的资料请关注脚本之家其它相关文章!

相关文章

  • vue样式穿透 ::v-deep的具体使用

    vue样式穿透 ::v-deep的具体使用

    这篇文章主要介绍了vue样式穿透 ::v-deep的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • vue3 $attrs和inheritAttrs的用法说明

    vue3 $attrs和inheritAttrs的用法说明

    这篇文章主要介绍了vue3 $attrs和inheritAttrs的用法说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • vue input组件如何设置失焦与聚焦

    vue input组件如何设置失焦与聚焦

    这篇文章主要介绍了vue input组件如何设置失焦与聚焦,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • Vue+Vant实现7天日历展示并在切换日期时实时变换功能

    Vue+Vant实现7天日历展示并在切换日期时实时变换功能

    本文介绍了如何利用Vue和Vant框架结合moment.js插件来实现一个7天日历展示功能,在这个功能中,用户可以在切换日期时看到界面的实时变化,此外,文章还提供了代码实现和效果测试的详细步骤,帮助开发者能够顺利完成类似的项目开发
    2024-10-10
  • 使用konva和vue-konva库实现拖拽滑块验证功能

    使用konva和vue-konva库实现拖拽滑块验证功能

    这篇文章主要介绍了使用konva和vue-konva完成前端拖拽滑块验证功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • elementUI实现级联选择器

    elementUI实现级联选择器

    这篇文章主要为大家详细介绍了elementUI实现级联选择器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • Webpack+Vue如何导入Jquery和Jquery的第三方插件

    Webpack+Vue如何导入Jquery和Jquery的第三方插件

    本文主要介绍了Webpack+Vue导入Jquery和Jquery的第三方插件的方法,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • vue watch监听变量值的实时变动示例详解

    vue watch监听变量值的实时变动示例详解

    这篇文章主要介绍了vue 监听变量值的实时变动 watch,使用字符串形式的侦听器函数,还有一种是使用函数形式的侦听器函数,本文通过示例代码介绍的非常详细,需要的朋友可以参考下
    2023-08-08
  • vue.js+boostrap项目实践(案例详解)

    vue.js+boostrap项目实践(案例详解)

    这篇文章主要介绍了vue.js+boostrap项目实践(案例详解)的相关资料,本文图文并茂介绍的非常详细,具有参考借鉴价值,需要的朋友可以参考下
    2016-09-09
  • 详解@Vue/Cli 3 Invalid Host header 错误解决办法

    详解@Vue/Cli 3 Invalid Host header 错误解决办法

    这篇文章主要介绍了详解@Vue/Cli 3 Invalid Host header 错误解决办法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01

最新评论