VueJS中如何创建与使用自定义modifier(修饰符)
Vue 自定义 Modifier 实现与使用方案
Vue 中的自定义 modifier 主要分两类:v-model 绑定的自定义修饰符、自定义指令的自定义修饰符,两类场景的实现逻辑有区别,核心思路都是在原有响应式绑定的链路中加一层拦截:拿到输入值/事件触发时机后,根据传入的修饰符标记执行自定义的转换、校验、特殊逻辑,再把处理后的结果交回Vue响应式流程即可。
一、具体实现参考
1. v-model 自定义修饰符
这类修饰符主要用来扩展v-model的内置能力,官方内置的.trim、.number、.lazy就属于这类实现,业务开发中可以自己封装常用的格式化逻辑,比如输入自动保留小数位、自动首字母大写、自动过滤特殊字符等。
以Vue3为例,组件内部通过modelModifiers props接收传入的修饰符集合,默认值为空对象,在值更新的回调中判断对应修饰符是否存在,执行对应处理即可:
<!-- 自定义数字输入组件 NumberInput.vue --> <template> <input type="text" :value="modelValue" @input="handleInput" /> </template> <script setup> const props = defineProps({ modelValue: [Number, String], // 固定字段,接收v-model上挂载的所有修饰符 modelModifiers: { default: () => ({}) } }) const emit = defineEmits(['update:modelValue']) const handleInput = (e) => { let val = e.target.value // 存在.toFixed修饰符时,自动保留2位小数 if (props.modelModifiers.toFixed) { const num = parseFloat(val) val = isNaN(num) ? val : num.toFixed(2) } // 存在.capitalize修饰符时,自动首字母大写 if (props.modelModifiers.capitalize) { val = val.charAt(0).toUpperCase() + val.slice(1) } emit('update:modelValue', val) } </script>
如果是Vue2项目,修饰符会挂载在vnode的model配置下,可以通过this.$vnode.data.model.modifiers拿到,处理逻辑和Vue3一致。
2. 自定义指令修饰符
这类修饰符用来扩展自定义指令的行为,比如给长按指令加只触发一次的标记、给权限指令加禁用而非隐藏的标记等。自定义指令的钩子函数会接收binding参数,其中的modifiers字段就是当前指令上挂载的所有修饰符集合,直接判断对应key的布尔值即可执行分支逻辑。
比如实现一个支持.once修饰符的全局长按指令v-longpress:
// main.js 全局注册指令 app.directive('longpress', { mounted(el, binding) { // 解构拿到修饰符 const { once } = binding.modifiers let pressTimer = null let hasTriggered = false const startPress = (e) => { // 传了.once且已经触发过,直接拦截 if (once && hasTriggered) return // 非鼠标左键点击不触发 if (e.type === 'mousedown' && e.button !== 0) return pressTimer = setTimeout(() => { // 执行绑定的回调 binding.value() hasTriggered = true }, 500) // 长按500ms触发 } const cancelPress = () => { if (pressTimer) { clearTimeout(pressTimer) pressTimer = null } } // 绑定鼠标、触摸事件 el.addEventListener('mousedown', startPress) el.addEventListener('touchstart', startPress) el.addEventListener('mouseup', cancelPress) el.addEventListener('mouseleave', cancelPress) el.addEventListener('touchend', cancelPress) } })
二、使用方式
- v-model自定义修饰符:和内置修饰符用法完全一致,直接在v-model后链式追加
.修饰符名即可,支持同时传多个修饰符:
<template> <!-- 同时启用保留2位小数、首字母大写两个修饰符 --> <NumberInput v-model.toFixed.capitalize="formData.amount" /> </template> <script setup> import { reactive } from 'vue' const formData = reactive({ amount: '' }) </script>
- 自定义指令修饰符:在指令名后链式追加
.修饰符名即可,不需要额外传参:
<template> <!-- 普通用法:每次长按都触发回调 --> <button v-longpress="showDeleteTip">长按删除</button> <!-- 加.once修饰符:长按仅触发一次回调 --> <button v-longpress.once="showNoviceGuide">长按显示新手引导</button> </template>
开发注意
- 自定义修饰符命名不要和Vue内置修饰符重名,避免逻辑覆盖冲突
- 修饰符本质是布尔类型的标记位,如果需要传动态参数,不要用修饰符实现,改用指令参数、v-model参数的写法更合适
- 多个修饰符链式调用时没有顺序要求,内部只要判断对应key是否为true就会执行对应逻辑
内容的提问来源于stack exchange,提问作者mohammad rida
相关产品推荐
相关产品推荐

