尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Vuetify v-model 深度指南:双向绑定、受控模型与多模型属性绑定

Vuetify v-model 深度指南:双向绑定、受控模型与多模型属性绑定 Vuetify v-model 深度指南双向绑定、受控模型与多模型属性绑定【免费下载链接】vuetify Vue Component Framework项目地址: https://gitcode.com/gh_mirrors/vu/vuetifyv-model 是 Vue 内置指令用于在组件与父级之间建立双向数据绑定。在 Vuetify 中几乎所有表单类组件如 VTextField、VCheckbox、VSelect与状态类组件如 VList、VTabs都以model-value/update:model-value协议对外暴露双向绑定能力。本文以 packages/docs/src/pages/en/concepts/v-model.md 为主线结合 Vuetify 源码中useProxiedModel组合式函数的实现讲解受控与非受控模型的区别、多属性绑定v-model:focus、v-model:selected等的正确用法以及如何利用这些机制实现静态值、条件拦截等高级场景。读完本文你将能够准确理解 Vuetify 中v-model的底层协议与受控/非受控判定规则熟练使用v-model:prop绑定组件的特定属性在需要锁定值、拦截非法输入时正确实现受控模型。什么是 v-modelv-model 是 Vue 内置指令允许你在组件与其父级之间创建双向数据绑定。它最常用于表单元素——输入框、复选框、下拉选择框等——将元素的值与父组件中的某个数据属性绑定起来。在 Vuetify 中这一机制被大量应用于组件 APIv-text-field、v-select、v-checkbox等表单组件的输入值v-list的选中项、展开项与激活项v-tabs的当前标签页v-dialog、v-bottom-sheet的显隐状态。底层上Vuetify 的每个组件都把可绑定状态声明为modelValue或具名属性prop并对外发出update:modelValue或update:属性名事件。这条prop 事件的约定正是 Vue 的 v-model 协议。v-model 的两种绑定形式v-model 指令在 Vuetify 中有两种写法分别对应默认模型与具名模型v-model是model-value与update:model-value的简写形式v-model:prop用于把组件的特定属性绑定为模型如v-model:focus、v-model:selected。例如下面这段代码template v-text-field v-modelfoo / /template script setup import { shallowRef } from vue const foo shallowRef(foo) /script与下面的完整写法完全等价template v-text-field :model-valuefoo update:model-valueonUpdateModel / /template script setup import { shallowRef } from vue const foo shallowRef(foo) function onUpdateModel (value) { foo.value value } /script在 Vuetify 源码中VTextField在 packages/vuetify/src/components/VTextField/VTextField.tsx 中明确声明了这一协议props 包含modelValueemits 包含update:modelValue随后在setup里调用useProxiedModel(props, modelValue, ...)生成可读写模型。也就是说组件内部所有对model.value的赋值最终都会转化为对父级的update:modelValue事件通知。受控Controlled与非受控Uncontrolled模型理解 Vuetify 双向绑定的关键在于受控与非受控的区分如果 prop 与事件同时被定义模型是受控的prop 的值被当作唯一数据源value 始终以 prop 为准如果只定义了 prop没有对应 update 事件模型是非受控的prop 仅被用作初始值之后由组件内部状态接管。这一判定逻辑在 packages/vuetify/src/composables/proxiedModel.ts 中实现通过检查当前组件实例的vnode.props是否同时包含modelValue或 kebab-case 形式与onUpdate:modelValue来得到isControlled计算属性。当处于受控状态时get直接返回props[prop]set只发出update事件而不改动内部值非受控时内部internalref 才是值的主宰同时通过useToggleScope见 packages/vuetify/src/composables/toggleScope.ts在 prop 变化时把外部值同步进内部 ref。受控模型必须由外部处理更新如果新值没有被写回 prop组件将不会更新显示。这一特性可用于条件性忽略更新或阻止输入特定值——例如限制输入框只能包含数字或让弹窗在特定业务状态下无法关闭。对应的单元测试 packages/vuetify/src/composables/tests/proxiedModel.spec.ts 完整验证了上述行为should use prop value if definedprop 存在时以其为初值且内部赋值会发出update:fooshould always use prop value if update listener defined一旦绑定了onUpdate:foo内部值不再自行变化直到父级把 prop 更新回来should use internal value if prop not defined未传 prop 时由内部状态接管赋值仅改变内部值并发出事件should switch to using prop when it is defined运行期间父级补传 prop 后模型自动切换为受控。用 noop 事件实现静态值通过定义带初始值的 prop 定义 noop 事件的组合可以让组件的值保持静态、不可变更template v-text-field model-valueFoobar update:model-valueonUpdateModel / /template script setup function onUpdateModel (value) { // noop } /script这段代码中model-valueFoobar提供了固定值而onUpdateModel是一个空函数——它同时满足了prop 与事件都已定义的受控条件却又丢弃了所有更新。从useProxiedModel的源码看由于isControlled为真任何内部写入都只触发事件、不影响展示值因此输入框会一直保持 Foobar。这种做法与readonly属性的区别在于它是通过值不回流实现的软锁定适合需要完全接管输入语义的场景。绑定组件的特定属性某些组件具有可绑定的特定属性例如 v-list 和 v-text-field。此时应使用v-model:prop语法template v-list v-model:activeactive v-model:openedopened v-model:selectedselected / v-text-field v-modelmodel v-model:focusfocus / /template script setup import { shallowRef } from vue const active shallowRef([]) const opened shallowRef([]) const selected shallowRef([1]) const model shallowRef() const focus shallowRef(false) /script这些具名模型在源码中有清晰的对应实现v-model:focus / v-model:focused焦点状态是一个可绑定模型。VTextField的 emits 声明了update:focused而 packages/vuetify/src/composables/focus.ts 中的useFocus通过useProxiedModel(props, focused)把focused做成受控模型提供focus()与blur()方法驱动它。事实上VAutocomplete、VCheckbox、VCombobox、VField、VFileInput、VNumberInput、VOtpInput、VRangeSlider等组件都遵循同一模式统一对外发出update:focused事件。v-model:selected / v-model:active / v-model:opened这三个模型来自嵌套列表体系。packages/vuetify/src/composables/nested/nested.ts 中useNested分别对selected、activated、opened调用useProxiedModel并通过transformIn/transformOut在数组与Set之间转换v new Set(Array.isArray(v) ? v.map(i toRaw(i)) : v)与v [...v.values()]从而对外暴露稳定的数组值、对内使用高效的 Set 结构。VList在 packages/vuetify/src/components/VList/VList.tsx 中通过makeNestedProps继承这些模型 prop并声明了update:selected、update:activated、update:opened事件。transformIn / transformOut模型值的内部转换useProxiedModel的签名如下见 packages/vuetify/src/composables/proxiedModel.tsuseProxiedModel(props, prop, defaultValue?, transformIn?, transformOut?)transformIn把外部传入的 prop 值转换为内部模型使用的形态如数组 → SettransformOut把内部模型值转换为对外 emit 的形态如 Set → 数组。VTextField也用到了这一机制它对modelValue做了Object.is(v, -0)的特判把-0规范化为字符串-0避免数值边界值引发状态漂移。理解了这两个参数你就明白为什么 Vuetify 组件对外文档中的数据类型数组、布尔、字符串与内部实现Set、ref可以不一致——转换层由useProxiedModel统一完成。实践要点与注意事项受控与非受控不要混用同一模型要么只传 prop非受控prop 只是初值要么 prop 事件成对出现受控。只传 prop 却期望父级值实时跟随组件内部变化是不会生效的。具名模型与默认模型互不干扰v-model与v-model:focus可同时使用它们分别对应modelValue与focused两条独立的 prop/事件通道。静态锁定用 noop 事件需要只读但保持双向绑定协议时model-value noop update是最直接的方式。数组类模型的值语义v-model:selected、v-model:opened等以数组形态对外交互如selected初值为[1]修改数组即触发update:selected组件内部会自动完成与 Set 的互转。prop 命名支持 kebab-caseuseProxiedModel通过toKebabCase(prop)同时检查 camelCase 与 kebab-case 两种写法如modelValue与model-value因此模板中两种写法均可且受控判定对两者一视同仁。结语v-model 在 Vuetify 中并非魔法而是一条高度统一的prop update 事件协议其核心引擎是useProxiedModel组合式函数。掌握受控/非受控判定、v-model:prop具名绑定以及transformIn/transformOut转换机制你不仅能更准确地使用文档中出现的各种v-model形式也能在自己封装基于 Vuetify 的业务组件时复刻出一致的双向绑定体验。相关源码可直接在仓库中查阅packages/vuetify/src/composables/proxiedModel.ts、packages/vuetify/src/components/VTextField/VTextField.tsx、packages/vuetify/src/components/VList/VList.tsx以及测试文件 packages/vuetify/src/composables/tests/proxiedModel.spec.ts。【免费下载链接】vuetify Vue Component Framework项目地址: https://gitcode.com/gh_mirrors/vu/vuetify创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表