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

