uni-app 的 @click 没水波纹是因跨端一致性设计,默认屏蔽视觉反馈;hover-class 仅部分平台生效;三端通用需手动实现 touchstart/touchend 触发的 DOM 水波纹动画。

uni-app 的 @click 为什么没水波纹?
因为 uni-app 默认不提供任何视觉点击反馈——这不是 bug,是跨端一致性设计。H5 有 :active,App 端(iOS/Android)原生控件有压暗/水波纹,但 uni-app 渲染层统一屏蔽了这些,避免小程序、App、H5 表现不一致。你绑了 @click,点下去没反应,用户真的会怀疑自己没点上。
用 hover-class 最快,但只在部分平台生效
hover-class 是 uni-app 官方推荐的轻量方案,写法简单:
<button hover-class="btn-hover" @click="handleClick">提交</button>
.btn-hover 里改背景色、opacity 或 transform 即可。但它有硬限制:
- 微信小程序:支持,但需开启
hover-stop-propagation防止父级也触发 - H5:支持,但仅限
<button></button>和<view></view>(且需设置cursor: pointer) - App 端(iOS/Android):完全不生效,连伪类都不触发
所以它只适合 H5 + 小程序混合项目,且对 App 无要求的场景。
App/H5/小程序三端通用:手动实现水波纹 DOM 动画
核心思路是监听 touchstart 获取点击坐标,动态插入一个绝对定位的圆形 <view></view>,用 CSS 动画控制 scale + opacity。关键点:
- 必须用
touchstart/touchend,不能用click,否则 iOS 上延迟明显 - 坐标计算要用
event.touches[0],不是event.detail.x - 容器必须设
position: relative且overflow: hidden - 动画时长建议设为
600ms,和setTimeout重置逻辑对齐
示例片段(精简版):
<view class="ripple-container" @touchstart="onTouchStart" @touchend="onTouchEnd">
<view class="btn">确定</view>
<view v-if="showRipple" class="ripple-effect" :style="{left: rippleX + 'px', top: rippleY + 'px'}"></view>
</view>
JS 中 onTouchStart 要调用 uni.createSelectorQuery() 拿容器宽高,再算出波纹中心偏移,否则波纹会飞出按钮范围。
uView1 的水波纹为啥 uView2 删了?
uView2 移除了内置水波纹,官方理由是「减少默认样式侵入、提升渲染性能」。实际影响是:
- 升级 uView2 后,原来带
ripple属性的<u-button></u-button>会彻底静音 - 如果你依赖这个效果,得自己补一层 wrapper 组件,或回退到 uView1 的
u-button源码逻辑 - 别直接复制 uView1 的 ripple 实现到 uView2 项目里——它的 class 命名和 scoped 样式机制已不兼容
最稳妥的做法:把水波纹逻辑抽成独立 mixin 或 composables,三端共用一套坐标计算 + 动画控制逻辑,而不是绑定某个 UI 库的内部结构。


















