单向数据流
- 单向数据流是Vue组件一个非常明显的特征,不应该在子组件中直接修改props的值
- 如果传递的prop仅仅用作展示,不涉及修改,则在模板中直接使用即可
- 如果需要对prop的值进行转化然后展示,则应该使用computed计算属性
- 如果prop的值用作初始化,应该定义一个子组件的data属性并将prop作为其初始值
组件之间的通信
- 父子组件的关系可以总结为
prop
向下传递,事件event
向上传递 - 祖先组件和后代组件(跨多代)的数据传递,可以使用
provide
和inject
来实现 - 跨组件或者兄弟组件之间的通信,可以通过
eventBus
或者vuex
等方式来实现
封装的组件如何实现v-model的数据双绑的效果
以下两种通常是我们的实现方式, 看着就很麻烦
- 通过emit将事件派发到父组件,prop将数据传到子组件
每个父组件都要实现
changeValue
方法来接收数据并更新数据
// 子组件
<template>
<div>
<van-button @click="add" type="default">加一</van-button>
<div>
{{countsVal}}
</div>
<van-button @click="reduce" type="default">减一</van-button>
</div>
</template>
<script>
export default {
props: {
value: Number
},
model: {
prop: 'value',
event: 'input'
},
data () {
return {
// props的初始化比data的初始化要靠前
countsVal: this.value
}
},
methods: {
add () {
this.countsVal++
this.$emit('add', this.countsVal)
},
reduce() {
this.countsVal--
this.$emit('reduce', this.countsVal)
}
}
};
</script>
// 父组件
<template>
<div>
<counter :value='value' @add='changeValue' @reduce='changeValue'/>
</div>
</template>
<script>
export default {
data () {
return {
value: 10
}
},
methods: {
changeValue (data) {
this.value = data
}
}
};
</script>
- 将加减执行的回到函数通过父组件传到子组件中实现改变数据
每个父组件都要实现
add
和reduce
两个方法
// 子组件
<template>
<div>
<van-button @click="add" type="default">加一</van-button>
<div>
{{countsVal}}
</div>
<van-button @click="reduce" type="default">减一</van-button>
</div>
</template>
<script>
export default {
props: {
value: Number,
add: Function,
reduce: Function
}
};
</script>
// 父组件
<template>
<div>
<counter :value='value' :add='add' :reduce='reduce'/>
</div>
</template>
<script>
export default {
data () {
return {
value: 10
}
},
methods: {
add (data) {
this.value++
},
reduce (data) {
this.value--
}
}
};
</script>
通过v-model
语法糖实现,父子组价的数据双绑
Vue内置了v-model指令,v-model 是一个语法糖,可以拆解为 props: value 和 events: input。就是说组件只要提供一个名为 value 的 prop,以及名为 input 的自定义事件,满足这两个条件,使用者就能在自定义组件上使用 v-model,戳这里看model配置
// 子组件
<template>
<div>
<van-button @click="changeVal(1)" type="default">加一</van-button>
<div>
{{countsVal}}
</div>
<van-button @click="changeVal(-1)" type="default">减一</van-button>
</div>
</template>
<script>
export default {
props: {
value: Number
},
data () {
return {
// props的初始化比data的初始化要靠前
countsVal: this.value
}
},
methods: {
changeVal (data) {
this.countsVal += parseInt(data)
this.$emit('input', this.countsVal)
}
}
}
</script>
// 父组件只需要通过v-model将数据传进去就好了
<template>
<div>
<counter v-model='counts'/>
</div>
</template>
<script>
import counter from './base/counter'
export default {
components: {
counter
},
data () {
return {
counts: 10
}
}
}
</script>