文章目录
总结
v-model的本质是v-bind加上@input,实现数据双向绑定- 父组件和子组件之间通信:
- 通过
props自定义属性,实现从父到子的数据传送 - 通过
emit自定义事件,实现从子到父的数据传送 - 二者相结合,实现父子组件之间的数据双向绑定
- 通过
- 在父组件里,可以简化 为
v-model操作,前提是子组件emit的事件必须是update:xxx v-model的默认参数(即绑定的属性名)是modelValue- 对于原生HTML元素,
v-model无需指定属性名,因为Vue知道取哪个属性名
- 对于原生HTML元素,
- 同一个子组件里可通过多个
v-model绑定多个属性,只需用参数区分开
环境
- Ubuntu 24.04
- Chrome Version 146.0.7680.164 (Official Build) (64-bit)
- VSCode 1.109.5
- npm 11.6.2
- Vue 3.5.32
准备
创建一个Vue项目。创建过程略,具体可参见 https://blog.csdn.net/duke_ding2/article/details/159510007 。
关于props,参见 https://blog.csdn.net/duke_ding2/article/details/159696940 。
关于emit,参见 https://blog.csdn.net/duke_ding2/article/details/159779784 。
v-model
基础
修改 App.vue 如下:
html
<template>
<div>
<input v-model="searchText" />
<div>{{ searchText }}</div>
<button @click="searchText = Math.random()">随机数</button>
</div>
</template>
<script>
export default {
data() {
return {
searchText: ''
}
}
}
</script>
效果如下:
- 点击按钮时,生成一个随机数:

- 用户可以修改输入框的数据:

本例中,通过 v-model ,实现了数据(变量 searchText )与显示的"双向绑定":
- 当数据的值变化时(比如点击按钮,生成随机数),输入框里的数据会同步变化
- 当输入框里的数据被修改时,数据的数值会同步变化
注意这行代码:
html
<input v-model="searchText" />
模板编译器会对 v-model 进行更冗长的等价展开。因此上面的代码其实等价于下面这段:
html
<input
:value="searchText"
@input="searchText = $event.target.value"
/>
其中:
:value表示从searchText变量到输入框显示的绑定@input表示在编辑输入框时,把数据修改同步到searchText变量
组件
在使用子组件时,要想把"父组件里的数据"和"子组件里的显示"做双向绑定,同理也需要 :value 和 @input ,但不同的是:
:value:由于其来源是父组件,所以需要通过props设置自定义属性@input:由于其目的是父组件,所以需要通过emit把事件发送到父组件
创建 MyComponent.vue 文件如下:
html
<template>
<input :value="searchText" @input="$emit('update:searchText', $event.target.value)"/>
</template>
<script>
export default {
props: ['searchText'],
emits: ['update:searchText'],
}
</script>
可见,在子组件中,通过 props 接受父组件的数据,通过 emit 向父组件发送"数据修改"事件。
注意:本例中,emit的事件名是 update:searchText ,其实在本例中并不强制如此。
修改 App.vue 如下:
html
<template>
<div>
<MyComponent :searchText="searchText" @update:searchText="newValue => searchText = newValue"/>
<div>{{ searchText }}</div>
<button @click="searchText = Math.random()">随机数</button>
</div>
</template>
<script>
import MyComponent from './MyComponent.vue';
export default {
components: {
MyComponent
},
data() {
return {
searchText: ''
}
}
}
</script>
可见,在父组件中,通过自定义属性 :searchText 向子组件传送数据,通过自定义事件 @update:searchText 接收子组件的"数据修改"事件,并同步修改变量 searchText 。
这样,就实现了父组件数据和子组件显示之间的双向绑定。
注意:本例中,自定义事件名是 update:searchText ,其实换成的其它如 updateSearchText 也没有问题。
v-model
之所以使用 update:searchText 这种看起来有点"怪异"的写法,是因为在Vue里,使用这种方法,则在父组件可以简化为 v-model 操作。
找到 App.vue 的如下代码:
html
<MyComponent :searchText="searchText" @update:searchText="newValue => searchText = newValue"/>
将其修改为:
html
<MyComponent v-model:searchText="searchText"/>
同样也能达到双向绑定效果。
只需记住 update:xxx 是固定的写法。这样父组件就可以通过 v-model 来简化。
参数与默认绑定属性名
上面的例子里, v-model 有一个参数 searchText ,该参数代表绑定的属性名。
注意:在本例中,该参数不能省略:
html
<MyComponent v-model="searchText"/>
这是不行的,因为Vue需要知道绑定的属性名是什么。如果不显式指定,则缺省绑定的属性名是 modelValue 。
也就是说,如果子组件只接收一个自定义属性,则为了简化,可以将其命名为 modelValue ,此时父组件的 v-model 可以省略参数。
注意:文本开头的例子里,并没有指定属性名:
html
<input v-model="searchText" />
这是因为对于原生的HTML元素,Vue知道应该绑定哪个属性名。比如,对于 input ,默认绑定的属性名是 value 。
多个v-model绑定
既然通过参数可以区分不同的属性名,我们就可以在一个子组件里通过 v-model 绑定多个属性。
修改 MyComponent.vue 如下:
html
<template>
<div>
<input :value="searchText" @input="$emit('update:searchText', $event.target.value)"/>
<br />
<input :value="searchTitle" @input="$emit('update:searchTitle', $event.target.value)"/>
</div>
</template>
<script>
export default {
props: ['searchText', 'searchTitle'],
emits: ['update:searchText', 'update:searchTitle'],
}
</script>
修改 App.vue 如下:
html
<template>
<div>
<MyComponent v-model:searchText="searchText" v-model:searchTitle="searchTitle"/>
<div>{{ searchText }}</div>
<div>{{ searchTitle }}</div>
<button @click="searchText = Math.random()">随机数</button>
<button @click="searchTitle = Math.random()">随机数</button>
</div>
</template>
<script>
import MyComponent from './MyComponent.vue';
export default {
components: {
MyComponent
},
data() {
return {
searchText: '',
searchTitle: ''
}
}
}
</script>
效果如下:

参考
https://cn.vuejs.org/guide/components/v-model.html