You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue2中如何正确结合使用click与touchstart事件?router-link默认支持吗?

在Vue2中结合click与touchstart的正确姿势,以及router-link的适配方案

我来一步步拆解你的问题,结合Vue2的实际开发场景给你靠谱的解决方案:

一、Vue2中正确使用click + touchstart的注意事项

直接同时绑定两个事件的话,在移动端会碰到同一操作触发两次的坑——touchstart触发后,浏览器会等待300ms判断是不是双击缩放,之后还会触发click。所以得做针对性处理:

  • 方案1:纯移动端场景,阻止默认行为
    如果你的应用只面向移动端,可以在touchstart事件里调用event.preventDefault(),直接阻止后续的click触发。注意这会禁用一些原生行为(比如文本选中、长按菜单),如果不需要这些的话很适用:

    <button @touchstart="handleAction" @click="handleAction">点击/触摸</button>
    
    methods: {
      handleAction(e) {
        e.preventDefault() // 阻止默认行为,避免触发click
        console.log('触发操作')
        // 你的业务逻辑
      }
    }
    
  • 方案2:兼容PC+移动端,避免重复触发
    如果需要同时支持PC和移动端,可以设置一个标记位,确保同一操作只执行一次:

    let isTouched = false
    methods: {
      handleTouchStart() {
        isTouched = true
        this.doBusiness()
      },
      handleClick() {
        if (!isTouched) {
          this.doBusiness()
        }
        // 300ms后重置标记,避免下次点击失效
        setTimeout(() => isTouched = false, 300)
      },
      doBusiness() {
        // 统一的业务逻辑
      }
    }
    

    也可以直接通过event.type判断,简化代码:

    handleAction(e) {
      if (e.type === 'touchstart') e.preventDefault()
      // 统一处理逻辑
    }
    

二、vue-router的默认支持情况

很明确:默认的<router-link>只绑定了click事件,完全不支持touchstart。这就导致移动端点击router-link时会有300ms的延迟,体验很不流畅。

三、为现有Vue2应用的router-link智能添加touchstart事件

如果你的项目已经用了大量<router-link>,不想逐个修改的话,这两个方案最实用:

方案1:全局混入自动处理(最省心)

用Vue的全局混入,自动给所有<router-link>元素绑定touchstart事件,同时处理重复触发问题。直接在main.js里加这段代码:

// main.js
Vue.mixin({
  mounted() {
    // 找到当前组件内所有的router-link元素
    const routerLinks = this.$el.querySelectorAll('router-link')
    routerLinks.forEach(link => {
      let isTouched = false
      // 保存原有的click处理函数
      const originalClick = link.onclick

      // 绑定touchstart事件
      link.addEventListener('touchstart', (e) => {
        isTouched = true
        e.preventDefault() // 阻止后续click触发
        originalClick && originalClick() // 执行原有的导航逻辑
      })

      // 重写click事件,避免触摸后重复触发
      link.onclick = (e) => {
        if (!isTouched) {
          originalClick && originalClick(e)
        }
        // 300ms后重置标记
        setTimeout(() => isTouched = false, 300)
      }
    })
  }
})

这样所有已存在的<router-link>都会自动获得touchstart支持,不需要修改任何组件代码,堪称“无痛升级”。

方案2:封装自定义RouterLink组件(更可控)

如果想更灵活地控制逻辑,可以封装一个自定义组件替换原生<router-link>:

<!-- components/CustomRouterLink.vue -->
<template>
  <router-link v-bind="$attrs">
    <slot></slot>
  </router-link>
</template>

<script>
export default {
  name: 'CustomRouterLink',
  data() {
    return {
      isTouched: false
    }
  },
  mounted() {
    const linkEl = this.$el
    const originalClick = linkEl.onclick

    linkEl.addEventListener('touchstart', (e) => {
      this.isTouched = true
      e.preventDefault()
      originalClick && originalClick()
    })

    linkEl.onclick = (e) => {
      if (!this.isTouched) {
        originalClick && originalClick(e)
      }
      setTimeout(() => this.isTouched = false, 300)
    }
  }
}
</script>

然后在main.js全局注册:

// main.js
import CustomRouterLink from './components/CustomRouterLink.vue'
Vue.component('CustomRouterLink', CustomRouterLink)

之后把项目里的<router-link>替换成<custom-router-link>就行,这样后续要修改触摸逻辑的话,只需要改这一个组件,维护起来更方便。

可选方案:用第三方库

如果不想自己写逻辑,可以用vue-touch(Vue2对应的是vue-touch@next),它封装了tap、swipe等触摸事件,直接替换click就能解决300ms延迟问题,不过要注意版本兼容性。


内容的提问来源于stack exchange,提问作者simhumileco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:29:50