拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Vuetify v-ripple 指令完全指南:为任意元素添加触摸与点击波纹反馈

Vuetify v-ripple 指令完全指南为任意元素添加触摸与点击波纹反馈【免费下载链接】vuetify Vue Component Framework项目地址: https://gitcode.com/gh_mirrors/vu/vuetifyv-ripple是 Vuetify 内置的指令级交互反馈方案它以水波扩散的形式呈现用户的点击、触摸与键盘操作让界面具备即时的按下感知。本文以官方文档 packages/docs/src/pages/en/directives/ripple.md 为主体结合仓库中 指令源码、样式定义 与 单元测试完整讲解基本用法、center/circle/stop修饰符、class/keys选项、自定义颜色以及组件内置rippleprop 的控制方式并深入剖析波纹的底层触发与动画机制。指令概述v-ripple指令用于向用户展示操作反馈。官方文档的定位是The ripple directive adds touch and click feedback to any element in the form of a water ripple即它以水波纹的形式为任意元素提供触摸与点击反馈。它具备两个显著特性适用范围广可以应用到任何块级元素block level element上无论是原生的div还是 Vuetify 组件。内置集成度高大量 Vuetify 组件已经内置了该指令例如v-btn、v-tabs-item等开箱即用无需手动挂载。从源码结构看ripple 指令目录 由三部分构成指令逻辑 index.ts、样式 VRipple.sass 以及 样式变量并配套有完整的 单元测试。基本用法启用基础波纹功能非常简单只需在组件或 HTML 元素上使用v-ripple指令即可。官方示例 usage.vue 展示了对原生div的用法template div classtext-center elevation-1 pa-12 text-headline-small v-ripple HTML element with v-ripple /div /template要点说明指令可以直接写在原生 HTML 元素上Vue 会自动将其注册为指令并使用。点击或触摸该元素时会从触点位置扩散出一圈波纹如果元素原本的position是static源码会在首次触发时自动将其调整为relative并在波纹结束后还原见 index.ts 与hide中的还原逻辑因此无需手动为宿主元素设置定位。在 Vuetify 的演示环境中指令通过全局注册可用在自定义工程中需要按需引入Ripple指令并注册Vuetify 完整安装时已自动注册。在单元测试 ripple.spec.ts 中with no value should be enabled用例验证了指令不带任何值时波纹默认启用这一行为——对应源码中的isRippleEnabled当值为undefined或 truthy 时视为启用。API 一览官方文档给出指令的 API 条目DirectiveDescriptionv-rippleThe ripple directive波纹指令从源码中的RippleDirectiveBinding类型index.ts可以还原出更完整的类型签名value指令值可为boolean也可为对象{ class?: string, keys?: string[] }false显式关闭波纹{ class: text-red }为波纹容器追加额外 class用于自定义颜色等{ keys: [Enter] }自定义键盘触发按键默认是[Enter, Space]。modifiers修饰符center波纹始终从元素中心扩散circle波纹以圆形适配元素常用于圆形按钮stop阻止嵌套元素上的事件触发外层波纹。传播控制v-ripple.stop当多个元素同时应用了 ripple 指令时典型场景是卡片内嵌按钮默认只有最内层的元素会显示波纹效果。官方文档 stop 示例 展示了这一点template v-row v-col cols12 v-card v-ripple v-card-textCard with ripple/v-card-text v-card-actions v-btnButton with ripple/v-btn /v-card-actions /v-card /v-col v-col cols12 v-card v-ripple v-card-text Outer card with ripple v-card-actions v-card v-ripple.stop v-card-text Inner card with coderipple.stop/code /v-card-text /v-card /v-card-actions /v-card-text /v-card /v-col /v-row /template第一张卡片中点击内部按钮时只有按钮产生波纹外层卡片的v-ripple不会同时触发第二张卡片中v-ripple.stop让内层卡片在自身被点击时不向外传播波纹——即使外层同样挂了 ripple。这里的实现原理值得注意v-ripple.stop并不会真正阻止mousedown/touchstart事件的传播这是它与mousedown.stop等常规做法的本质区别。源码中它通过一个私有符号stopSymbol来标记事件已被消费const stopSymbol Symbol(rippleStop)在 rippleShow 中事件一旦被某个元素处理就会在事件对象上写入e[stopSymbol] true外层元素的事件监听器收到该事件时若发现e[stopSymbol]已存在index.ts便直接返回从而保证同一交互只在一个元素上产生波纹。而当修饰符为stop时updateRipple 会为该元素绑定rippleStop监听器它只负责在事件对象上打上stopSymbol标记本身不产生波纹也不会拦截 DOM 事件继续冒泡——这正是文档强调的unlike other workarounds。单元测试中should only ripple on one element用例ripple.spec.ts验证了嵌套 ripple 只触发内层这一行为。选项Center居中波纹使用center选项时波纹将始终从目标元素的中心向外扩散而不是从点击位置开始。官方示例 option-center.vuetemplate div classtext-center elevation-1 pa-12 text-headline-small v-ripple.center HTML element with centered ripple /div /template从源码看center的处理位于 calculate当value.center为真时波纹的起点坐标直接取元素中心的偏移量centerX/centerY否则取localX - radius、localY - radius即触点减去波纹半径。此外键盘事件触发的波纹也一律使用居中效果value.center element._ripple.centered || isKeyboardEvent(e)也就是说即使没有显式写.center通过键盘如 Enter / Space激活的波纹也总是从中心扩散以保证焦点操作时的视觉效果一致。自定义波纹颜色默认情况下波纹使用currentColor作为颜色见 VRipple.sass因此它天然继承宿主元素的文字颜色。若要精确控制颜色官方推荐使用工具类helper class。官方示例 misc-custom-color.vue 通过指令对象值中的class选项传入主题色工具类template v-list v-list-item v-forcolor in [primary, secondary, info, success, warning, error] :keycolor v-ripple{ class: text-${color} } v-list-item-titleItem with {{ color }} class/v-list-item-title /v-list-item /v-list /template其工作原理为源码 show 在创建波纹容器时将value.class拼接到v-ripple__container的 className 上由于波纹动画元素v-ripple__animation使用background: currentColor容器上的text-primary/text-red等文本颜色类会通过color: inherit一级级继承下去从而改变波纹颜色updateRipple会读取对象值中的class并保存到el._ripple.classindex.ts供每次rippleShow时取出。同理circle修饰符在calculate中会调整波纹的缩放系数与半径算法scale 0.15半径与元素宽度相关index.ts适合应用在圆形按钮等元素上。组件内置 ripple 属性不少组件提供了rippleprop用于直接控制其内置的波纹效果。官方示例 misc-ripple-in-components.vue 以v-btn展示了三种形态——默认开启、显式关闭、以及通过对象值定制行为template v-row classpy-12 justify-space-around v-btn colorprimary With ripple (default) /v-btn v-btn :ripplefalse colorprimary Without ripple /v-btn v-btn :ripple{ class: text-red } varianttext With red ripple /v-btn /v-row /template可以看到组件级rippleprop 与指令的对象值语法保持一致同样支持class、center等选项对象中的keys同样生效。以 VBtn 为例其内部直接导入了指令源码import vRipple from /directives/ripple import type { RippleDirectiveBinding } from /directives/ripple并在渲染时通过!isDisabled.value props.ripple决定是否将vRipple指令应用到按钮上VBtn.tsx。这意味着rippleprop 默认启用当按钮处于禁用状态时波纹被抑制:ripplefalse时指令虽然仍在但值被置为falseisRippleEnabled 返回假updateRipple会移除全部监听器并隐藏已有波纹。除了v-btn文档还点明v-tabs-item等组件同样内置了 ripple在自定义封装组件时也可以参考这一模式直接复用 ripple 指令 获得一致的交互体验。源码级原理波纹是如何触发的事件监听与状态机updateRipple 负责指令的挂载与更新它会在元素上维护一个_ripple内部状态对象记录enabled、centered、circle、class、touched、isTouch以及触摸延迟定时器等字段。启用时enabled !wasEnabled指令会为该元素绑定一系列监听器事件处理器说明touchstartpassiverippleShow触摸开始touchendpassiverippleHide触摸结束touchmovepassiverippleCancelShow触摸滑动取消波纹touchcancelrippleHide触摸被系统打断mousedownrippleShow鼠标按下mouseup/mouseleaverippleHide鼠标释放/离开keydownkeyboardRippleShow键盘触发默认 Enter / SpacekeyupkeyboardRippleHide键盘释放blurfocusRippleHide焦点移出时隐藏此外还有dragstart监听——源码注释提到锚点元素anchor被拖拽时会导致其他隐藏逻辑失效对应历史 issue #1537因此需要额外绑定rippleHide。触摸延迟与防抖触摸事件有一个 80ms 的延迟常量DELAY_RIPPLEindex.ts。rippleShow在收到touchstart时不会立刻渲染波纹而是先记录showTimerCommit回调并设置定时器若在 80ms 内发生了touchmove滑动rippleCancelShow会取消该回调避免滚动页面时误触波纹。touchend到来时如果showTimerCommit仍存在则会立即执行它以保证短暂的触摸也显示波纹然后重新排队隐藏。这一套机制在rippleHideindex.ts中有完整的注释说明。同时源码还对移动端常见的触摸事件被转译为鼠标事件做了防护一旦isTouch被标记为真后续的鼠标事件将不再触发波纹index.ts。动画生命周期波纹的视觉实现由两个 DOM 节点完成v-ripple__container铺满宿主元素、overflow: hidden、pointer-events: none的容器v-ripple__animation圆形的动画元素背景为currentColor宽度/高度为radius * 2。show中index.ts会先加上--enter与--visible状态以初始缩放scale3d(0.3,0.3,0.3)圆形模式为 0.15定位到触点或中心随后借助双层requestAnimationFrame切换到--in状态并把 transform 过渡到translate(centerX, centerY) scale3d(1,1,1)完成扩散动画。hide则计算已存活时间至少保留 250ms 后再切换到--out淡出并在 300ms 后移除容器节点。对应的 VRipple.sass 定义了过渡--in transition: $ripple-animation-transition-in opacity: $ripple-animation-visible-opacity --out transition: $ripple-animation-transition-out opacity: 0而 样式变量 定义了具体的时长与透明度$ripple-animation-transition-in: transform .25s settings.$decelerated-easing, opacity .1s settings.$decelerated-easing !default; $ripple-animation-transition-out: opacity .3s settings.$decelerated-easing !default; $ripple-animation-visible-opacity: calc(.25 * var(--v-theme-overlay-multiplier)) !default;注意两个细节扩散阶段 transform 用时 0.25s、透明度 0.1s淡出阶段用时 0.3s均使用 Vuetify 的减速缓动曲线decelerated-easing波纹的可见透明度并非固定值而是calc(.25 * var(--v-theme-overlay-multiplier))——它受主题的 overlay 倍率影响因此在不同主题/对比度设置下波纹浓度会自适应变化。同时样式为prefers-reduced-motion场景做了无障碍适配VRipple.sass在用户开启减少动态效果的系统偏好时波纹退化为仅 0.1s 的透明度过渡不再执行位移动画。指令生命周期Ripple指令对象index.ts实现了三个钩子mounted调用updateRipple完成首次初始化updated当binding.value ! binding.oldValue时依据旧值是否启用决定走绑定监听器还是移除监听器分支——这使:ripplefalse这类响应式切换可以即时生效对应测试should update element property reactivelyunmounted调用removeListeners清理全部监听器并删除_ripple状态避免内存泄漏。总结v-ripple是 Vuetify 中小而美的交互设施对外它提供了center、circle、stop三个修饰符和class、keys两个对象选项既可一键启用也能精细定制对内它在 index.ts 中用stopSymbol解决了嵌套波纹冲突用 80ms 触摸延迟过滤滑动误触用双层requestAnimationFrame驱动扩散动画并通过主题 overlay 变量与prefers-reduced-motion兼顾了视觉一致性与无障碍体验。无论是直接在元素上使用v-ripple还是通过组件的rippleprop 控制如 VBtn你都可以为应用提供一致、流畅的点击反馈。【免费下载链接】vuetify Vue Component Framework项目地址: https://gitcode.com/gh_mirrors/vu/vuetify创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门