vue中的v-model
本文于 396 天之前发表,文中内容可能已经过时。
v-model 实际上就是 $emit(‘input’) 以及 props:value 的组合语法糖,在背后做了两件事:
- v-bind绑定value属性的值;
- v-on绑定input事件监听到函数中,函数会获取最新的值赋值到绑定的属性中;
一、v-model用在html标签上
1 2 3
| <input v-model="foo" /> 相当于⬇️ <input :value="foo" @input="foo = $event.target.value" />
|
checkbox 和 radio 使用 props:checked 属性和 $emit(‘change’) 事件。
select 使用 props:value 属性和 $emit(‘change’) 事件。
但是,除了上面列举的这些,别的都是 $emit(‘input’) 以及 props:value
二、v-model用在组件标签上
2.1、组件中非v-model实现双向数据绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| // 父组件 <template> <div class=''> <UserInfo :value="userName" @input="onInput"></UserInfo> <p>姓名:{{userName}}</p> </div> </template>
<script> import UserInfo from './components/UserInfo.vue' export default { data() { return { userName: '' } }, components: { UserInfo }, methods: { onInput(val) { this.userName = val } } } </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| // 子组件 <template> <div> <input type="text" :value="value" @input="handlerInput"> </div> </template>
<script> export default { props: { value: { type: String, default: '' } }, methods: { handlerInput(e) { this.$emit('input', e.target.value) } } } </script>
|
2.2、组件中v-model实现双向数据绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| // 父组件 <template> <div class=''> <UserInfo v-model="userName"></UserInfo> <p>姓名:{{userName}}</p> </div> </template>
<script> import UserInfo from './components/UserInfo.vue' export default { data() { return { userName: '' } }, components: { UserInfo } } </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| // 子组件 <template> <div> <input type="text" :value="value" @input="handlerInput"> </div> </template>
<script> export default { props: { value: { type: String, default: '' } }, methods: { handlerInput(e) { this.$emit('input', e.target.value) } } } </script>
|
1)修改传递参数的默认值
默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event,为了避免有时候的冲突,我们可以自定义事件;以下是在子组件中声明:
1 2 3 4
| model: { prop: 'myValue', event: 'myInput', }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| // 父组件 <template> <div class=''> <UserInfo v-model="userName"></UserInfo> <p>姓名:{{userName}}</p> </div> </template>
<script> import UserInfo from './components/UserInfo.vue' export default { data() { return { userName: '' } }, components: { UserInfo } } </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| // 子组件 <template> <div> <input type="text" :value="myValue" @input="handlerInput"> </div> </template>
<script> export default { model: { prop: 'myValue', event: 'myInput' }, props: { myValue: { type: String, default: '' } }, methods: { handlerInput(e) { this.$emit('myInput', e.target.value) } } } </script>
|
2)实践案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| // 父组件 <template> <div class=''> <Dialog v-model="dialogFlag" @confirm="confirm"></Dialog> <p>{{params}}</p> <md-button type="primary" @click="open">打开弹窗</md-button> </div> </template>
<script> import Dialog from './components/Dialog.vue' export default { data() { return { dialogFlag: false, params: '' } }, components: { Dialog }, methods: { open() { this.dialogFlag = true }, confirm(val) { this.params = val } } } </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| // 子组件 <template> <div> <md-dialog title="窗口标题" :closable="true" v-model="basicDialogFlag" :btns="basicDialog.btns" > 人生的刺,就在这里,留恋着不肯快走的,偏是你所不留恋的东西。 </md-dialog> </div> </template>
<script> export default { props: { value: { type: Boolean, default: false } }, data() { return { basicDialog: { btns: [ { text: '确认操作', handler: () => { this.onBasicConfirm() } } ] } } }, computed: { basicDialogFlag: { get() { return this.value }, set(value) { this.$emit('input', value) } } }, mounted() { }, methods: { onBasicConfirm() { this.basicDialogFlag = false this.$emit('confirm', '子组件确认操作已通知父组件') } } } </script>
|
3)扩展
Vue 2 中 .sync 修饰符的用法,父子组件如何通过 :prop.sync 和 $emit('update:prop') 进行双向绑定。
在 Vue 2 中,当父组件写:
1
| vue<Child :name.sync="username"></Child>
|
它等价于:
1
| vue<Child :name="username" @update:name="val => username = val"></Child>
|
也就是说:
- 父组件传给子组件
name 属性 - 子组件通过
$emit('update:name', newVal) 能直接更新父组件的 username
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| // 父组件 <template> <div> <h2>父组件</h2> <p>父组件的用户名: {{ username }}</p>
<Child :name.sync="username" /> </div> </template>
<script> import Child from './Child.vue'
export default { components: { Child }, data() { return { username: '张三' } } } </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| // 子组件 <template> <div> <h3>子组件</h3> <p>接收到的用户名: {{ name }}</p>
<button @click="changeName">修改用户名</button> </div> </template>
<script> export default { props: { name: { type: String, required: true } }, methods: { changeName() { const newName = this.name + '(子组件改过)' this.$emit('update:name', newName) } } } </script>
|