在React或者Vue这类MVVM框架中使用双向绑定是很常见的需求,最近项目中在使用Vue,今天来谈一谈Vue中双向绑定的实现。
先来说几句废话:什么是双向绑定?
把Model中的数据绑定到View中,然后更新Model时View会自动跟新,这叫单向绑定,而当用户改变View时Model中数据也能自动更新时,这叫双向绑定!
如何实现Vue中的双向绑定?有两种方式可供参考:
$emit 自定义事件处理机制
我们先来看一段代码:
// 父组件
<template>
<Child :data="value" v-on:selfEvent="handleFunc"></Child>
</template>
<script>
import Child from 'child.vue'
export default {
data(){
return {
value: '' // 对应Model
}
}
components:{ Child },
methods:{
handleFunc(val){
this.value = val
}
}
}
</script>
// 子组件
<template>
<div>
<label>请输入</label>
<input :value="data" @input="changeValue" /> // 对应View
</div>
</template>
<script>
export default {
props: {
data: {type: String,default: ''}
},
methods:{
changeValue(e){
this.$emit('selfEvent',e.target.value)
}
}
}
</script>
我们还从Model和View的视角分析,Model中的数据就是父组件中的定义的状态value,View就是子组件的输入框。
- 首先,子组件接收一个data属性来绑定输入框的value作为View展示的内容(单向绑定)。
- 然后,父组件中声明了一个自定义事件selfEvent并接收一个参数来处理Model(handleFunc方法),子组件中利用Vue内建的 $emit方法来触发自定义事件selfEvent并把当前输入框的值传递给父组件,以此实现双向绑定。
这个过程就像一个闭环:
v-model指令
v-model是最简单的实现双向绑定的方式了,只需要使用该指令绑定Model就可以了
<input type="text" v-model="data" />
可是我们有时候并不是简单的使用input,而是把它封装成一个组件来供其他组件使用,那我们如何保证组件之间的双向绑定呢?接下来讲一下本文的重点:自定义组件使用v-model
- v-model其实就是一个语法糖
<input type="text" v-model="data" />
<input type="text" :value=“data” @input="e=> data = e.target.value" />
这两者的效果是一样的。 按照这个思路,参考官方文档我们可以实现在自定义组件上使用v-model
// 父组件
<template>
<div>
<Test v-model="val"></Test>
</div>
</template>
<script>
import Test from '@/base/test/test.vue'
export default {
components: { Test },
data() {
return {
val: ''
}
}
}
</script>
// 子组件
<template>
<input type="text" :value="value" @input="$emit('input',$event.target.value)">
</template>
<script>
export default {
props: {
value: { type: String, default: '' }
}
}
</script>
- 一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件
但是像单选框、复选框我们并不希望利用默认的value和input事件,怎么处理呢,Vue提供了更为通用的写法。model选项可以解决这类问题
// 子组件
<template>
<input type="checked" :value="checked" @change="$emit('change',$event.target.checked)">
</template>
<script>
export default {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: { type: Boolean }
}
}
</script>
- 声明model选项,利用为名checked的prop和名为change的事件处理。
不管是用$emit方法还是使用v-model指令都可以很好的实现双向绑定,具体使用视情况而定。