核心区别
-
触发机制
- @tap :基于触摸手势,轻触按下并短时间松开触发;避免移动端的 300ms 点击延迟。
- @click :DOM 鼠标/指针点击事件,更偏 Web 语义,历史上在移动端可能存在 300ms 延迟。
-
跨端兼容
- @tap :跨平台统一,微信小程序/App/H5 都支持,映射到小程序的 bindtap 。
- @click :在 H5/App WebView 环境可用;在小程序端不保证一致行为,部分场景不会触发或表现不稳。
-
冒泡与阻止
- @tap :可用 Vue 修饰符 .stop (在小程序中会转换为 catchtap ,阻止冒泡)、 .capture 等。
- @click :按标准 DOM 事件处理修饰符;但在小程序端不一定生效。
-
事件语义
- @tap :移动优先手势;支持配套的 @longpress / @longtap 等。
- @click :Web 点击语义;适合 PC/H5 的鼠标或键盘交互。 项目建议
-
目标是微信小程序,统一使用 @tap 做交互绑定,保证跨端一致、响应更快。
-
仅在纯 H5 页面且确需 DOM 点击语义时再考虑 @click 。
-
需要阻止冒泡时,用 @tap.stop="handler" ;需要长按交互,用 @longpress="handler" 。
冒泡概念
-
冒泡是事件在目标元素触发后,沿着层级从子节点向父节点、再向更高祖先节点依次触发相同事件)
-
在小程序/uni-app中,触摸事件的冒泡对应 WeChat 的 bindtap 链路;阻止冒泡对应 catchtap 链路示意
-
目标元素触发 → 直接父元素触发 → 祖先元素触发 → 页面根容器触发
-
任何一个环节使用“阻止冒泡”,后续父级将不会再收到事件 在 uni-app 的写法
-
正常冒泡:子和父都会触发
<view class="parent" @tap="onParentTap"> <view class="child" @tap="onChildTap"></view> </view> -
阻止冒泡:只触发子,不再传到父
<view class="parent" @tap="onParentTap"> <view class="child" @tap. stop="onChildTap"></view> </view> -
捕获阶段优先(可选):父先于子触发
<view class="parent" @tap. capture="onParentTap"> <view class="child" @tap="onChildTap"></view> </view>
与 @click 的关系
-
@tap 是触摸手势,跨端一致,避免移动端点击延迟,推荐在小程序使用
-
@click 是 Web DOM 点击;在小程序端不保证一致行为,冒泡也不如 @tap 可控 你当前页面的影响点
-
底部栏 bottom-nav 中,图标是子元素,容器是父元素;若父容器以后绑定了 @tap ,图标的点击会冒泡到容器
-
需要只触发图标自身行为时,在图标上使用 @tap.stop="handler" 即可避免父级收到事件
冒泡效果没有显示的原因
-
父级没有监听:事件会“向上冒泡”,但只有父级绑定了同类型事件时你才会看到效果;
-
事件类型不一致:父子必须同为 tap 链路;用 @click 的父级无法接收子级的 @tap 。
-
被阻止传播:子级如果使用了 .stop 或在微信端使用了 catchtap ,父级不会收到。
-
组件差异:某些内置组件的交互可能改变传播行为;在小程序里统一用 @tap 更稳。 怎么做
-
给父容器绑定 @tap 以验证冒泡:
<view class="bottom-nav" @tap="onBottomNavTap"> <button class="submitOrder" @tap="submitOrder">下单</ button> </view>在脚本里加:
methods: { onBottomNavTap() { uni. showToast({ title: '父容器收到 tap', icon: 'none' }) } } -
如果仍希望子级触发但不让父级触发,改用 @tap.stop :
<button class="submitOrder" @tap. stop="submitOrder">下单</button> -
统一事件类型:确保父子都用 @tap ,不要父级 @click 子级 @tap 。