Vue3父子组件多层v-model双向绑定:子输入框与父变量同步方案
Vue3 父子组件双向绑定实现方案
核心原理
Vue3的v-model自定义组件绑定本质是语法糖,v-model:value="parentVariable"会自动给子组件传入名为value的prop,同时监听名为update:value的事件,父组件接收到事件后自动更新绑定的变量值,符合单向数据流规则,所有状态修改都由父组件统一维护。
具体实现
1. 基础写法(适合简单封装场景)
子组件直接绑定input的属性和事件,无需额外计算属性:
<!-- Child.vue --> <template> <!-- 输入框值绑定props传入的value,输入时触发更新事件通知父组件 --> <input :value="value" @input="$emit('update:value', ($event.target as HTMLInputElement).value)" /> </template> <script setup lang="ts"> // 声明接收父组件传入的value属性 defineProps<{ value: string }>() // 声明更新事件,命名固定为`update:绑定的prop名` defineEmits<{ 'update:value': [value: string] }>() </script>
父组件直接使用你写的写法即可,变量会自动双向同步:
<!-- Form.vue --> <template> <Child v-model:value="parentVariable"/> </template> <script setup lang="ts"> import { ref } from 'vue' import Child from './Child.vue' const parentVariable = ref('') </script>
2. 简化写法(适合子组件内部需要频繁操作绑定值的场景)
通过computed封装get/set,子组件内部可以直接用v-model绑定封装后的变量,写法更简洁:
<!-- Child.vue --> <template> <input v-model="inputValue" /> </template> <script setup lang="ts"> import { computed } from 'vue' const props = defineProps<{ value: string }>() const emit = defineEmits<{ 'update:value': [value: string] }>() const inputValue = computed({ // 取值时返回props的value get() { return props.value }, // 修改时触发更新事件通知父组件 set(newVal: string) { emit('update:value', newVal) } }) </script>
最佳实践
- 永远不要直接修改props:所有对父组件绑定值的修改都必须通过
emit发送事件通知父组件修改,严格遵守单向数据流规则,避免数据流混乱导致的难排查问题。 - 单输入组件优先用默认
v-model:如果子组件是只有一个核心绑定值的表单组件,可以省略v-model的后缀,默认绑定的prop名为modelValue,事件名为update:modelValue,父组件可以直接写<Child v-model="parentVariable" />,用法和原生输入框一致,更符合直觉。 - 多值绑定用不同后缀:如果子组件需要同时绑定多个值,可以给
v-model加不同后缀,例如<Child v-model:name="userName" v-model:age="userAge" />,子组件分别对应声明对应的prop和事件即可,比Vue2的.sync语法更清晰。 - 增加类型校验:使用TS时给props和emit添加类型定义,开发阶段就能提前发现参数传递错误。
内容的提问来源于stack exchange,提问作者Peter Toth
相关产品推荐
相关产品推荐

