Vue组件受控与非受控模式本质是状态归属权的选择:受控由父组件完全控制value并响应事件更新;非受控由子组件自主管理状态,父组件仅提供初始值;混合模式需隔离逻辑、明确切换条件,并覆盖边界场景。

Vue 组件设计中,实现受控与非受控模式的关键,在于明确状态归属权:值由父组件决定并同步更新,就是受控;由子组件自己维护、父组件只管初始值,就是非受控。二者不是技术难度问题,而是架构意图的选择。
受控组件:父组件掌握全部控制权
受控组件的 value(或 modelValue)完全来自 props,任何变更都必须通过事件(如 @update:modelValue 或 @input)通知父组件,由父组件决定是否更新自身状态。
- 使用 v-model 绑定时,本质是 :model-value + @update:model-value 的语法糖,父组件需用 ref 或 reactive 管理该值
- 适合需要表单联动、提交前校验、动态禁用/重置、跨组件同步等场景
- 切忌在子组件内部用 useState / ref 初始化同名值,否则会触发 “changing an uncontrolled input to be controlled” 警告
- 初始 props 值必须明确传入(哪怕为空字符串或 null),不能靠子组件 fallback,默认值逻辑应交由父组件处理
非受控组件:子组件自主管理状态
非受控组件内部用 ref 或 reactive 管理状态,父组件仅通过 defaultValue / defaultModelValue 提供初始化依据,不参与后续变更流程。
- 典型写法是接收 default-value prop,并在 setup 中用 ref 初始化内部状态
- 适用于搜索框临时过滤、模态框草稿、纯展示型编辑器等轻量、独立、无需外部干预的交互
- 注意:父组件后续修改 defaultValue 不会重置组件值(DOM input 的 value 不会变),这是与受控模式的本质区别
- 如需读取当前值(例如点击“提交”时),优先用 ref.value 或 inputRef.value,而非监听 props 变化
混合兼容模式:按需自动切换,但逻辑必须隔离
为提升组件通用性(尤其在 UI 库中),可支持两种模式共存:有 value/modelValue 且不为 undefined → 受控;否则 → 非受控。
立即学习“前端免费学习笔记(深入)”;
- 核心是定义一个内部 ref 作为唯一数据源,再用 watch 监听 props.value,仅在受控模式下同步它
- 禁止在受控分支里写 internalState.value = ...,也禁止在非受控分支里监听 value 变化
- 对外暴露 v-model 时,computed 的 set 必须 emit update:xxx,get 返回内部 ref 值
- 文档必须清晰标注:哪些 props 触发受控行为,哪些仅用于初始化
验证与边界注意事项
无论采用哪种模式,都要覆盖关键边界行为:
- 快速连续输入、焦点切换、键盘快捷键(如 Enter/Escape)是否稳定
- 父组件重置 props(如清空 value)后,组件是否响应正确
- 禁用态(disabled)下用户操作是否被合理拦截
- 服务端渲染(SSR)环境下 defaultValue 是否能正确 hydrate
- 测试时需分别验证受控和非受控两套生命周期路径


















