双向数据绑定指父组件数据更新可以自动同步到子组件上,同时,子组件也可以修改数据,通知到父组件上,从而实现数据的双向绑定。如下图,父组件通过 props 将数据传递给子组件,子组件 emit 事件将要修改的数据通知到父组件。
vue2
v-model
表单输入可以通过 v-model 实现数据的双向绑定,如 input 输入框:
<template>
<div id="app">
<div><input v-model="inputValue"></div>
<div>inputValue: {{inputValue}}</div>
</div>
</template>
v-model 本质是 v-bind:value 和 @input="value=$event" 的语法糖。即:子组件绑定的 props 是 value ,父组件要监听 input 事件。知道原理后,我们可以自己实现双向数据流。
自己实现
使用 v-model 语法糖
如果想使用 v-model 语法糖的话,子组件 AComponent 中 props 使用 value,通过 emit('input') 来通知父组件修改数据。
<template>
<div>
<span>{{value}}</span>
<button @click="changeValue">change</button>
</div>
</template>
<script>
export default {
name: 'AComponent',
props: {
value: String,
},
methods: {
changeValue
this.$emit('input', "new value")
},
}
}
</script>
父组件使用:
<AComponent v-model="aValue"></AComponent>
如果想要更改 prop 或事件名称,则需要在 AComponent 组件中添加 model 选项。
<template>
<div>
<span>{{title}}</span>
<button @click="changeValue">change</button>
</div>
</template>
export default {
model: {
prop: 'title',
event: 'change',
},
methods: {
changeValue
this.$emit('change', "new value")
},
}
}
不使用 v-model
子组件 AComponent:
<template>
<div>
<span>{{title}}</span>
<button @click="changeTitle">change title</button>
</div>
</template>
<script>
export default {
name: 'AComponent',
props: {
value: String,
},
methods: {
changeTitle(){
this.$emit('update:title', 'acomponent self change')
}
}
}
</script>
父组件使用:
<AComponent :title="aTitle" @update:title="updateTitle"></AComponent>
export default {
name: 'App',
components: {AComponent,},
data(){
return{
aTitle: 'aTitle',
}
},
methods: {
updateTitle(val){
this.aTitle = val
}
}
}
vue3
v-model 语法糖
v-model 语法糖与 vue2 不同,相当于绑定了 modelValue 属性和 update:modelValue 事件。
<input v-model="searchText">
相当于:
<input :modelValue="searchText" @update:modelValue="newVal => searchText=newVal">
同时,通过 v-model 可以绑定多个 v-model:
<template>
<div>
<span>{{modelValue}}</span>
<div>{{title}}</div>
<button @click="changeValue">change</button>
</div>
</template>
<script setup>
import { defineProps, defineEmits, } from 'vue'
defineProps({
modelValue: String,
title: String
})
const emit = defineEmits(['update:modelValue', 'update:title'])
const changeValue = () => {
emit('update:modelValue', 'new input value')
emit('update:title', 'ttt')
}
</script>
父组件:
<template>
<AComponent v-model="aVal" v-model:title="aTitle"/>
<div>{{aVal}}</div>
</template>
<script setup>
import AComponent from './components/AComponent.vue'
import { ref } from 'vue'
const aVal = ref('a')
const aTitle= ref('title')
</script>
组件 value 和 title 两个 props 都是双向绑定的。
自己实现
如果不借用 v-model 语法糖的话,同 vue2 一样,可以实现双向数据流。
总结
vue2 和 vue3 中, v-model语法糖含义不同,同时,vue3 中,借用 v-model 可以绑定多个双向数据。