前言
首先要了解的是,组件通信的几种情况:父子组件通信,隔代组件通信(父孙组件通信),兄弟组件通信。
通信方式
props 和 $emit
适用于父子组件通信
props 是从父组件向子组件传递数据,$emit 是从子组件向父组件传递数据,这是 Vue 组件通信的基础。
<!-- Parent.vue -->
<template>
<div>
<child :value="text" @input="handleValue"></child>
<h1>{{text}}</h1>
</div>
</template>
<script>
import Child from "./Child.vue";
export default {
data () {
return {
text: "父组件!"
}
},
components :{
Child
},
methods: {
handleValue (value) {
this.text = value; // 子组件传递过来的输入框数据
}
}
}
</script>
<!-- Child.vue -->
<template>
<input type="text" @input="handleInput" :value="value">
<!-- 此时的 value 是是从父组件传递过来的数据,'父组件' -->
</template>
<script>
export default {
props: ['value'],
methods: {
handleInput (e) {
this.$emit('input', e.target.value);
}
}
}
</script>
props 传递数据是单向传递的,只能由父组件向子组件传递,父组件中的数据发生改变,子组件中的数据也会随之改变。
ref 和 $parent / $children
适用于父子组件通信
通过 $ref 组件,父组件可以获取到子组件上所有的实例 data 和 方法,通过 $parent 子组件可以获取到父组件所有的实例 data 和 方法,通过 $children 父组件可以获取到子组件的实例 data 和 方法。
<!-- Parent.vue -->
<template>
<div>
<button @click="handleClick">+1</button>
<p>{{value}}</p>
<child ref="child"></child>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
data () {
return {
value: 0
}
},
components: {
Child
},
methods: {
handleClick () {
this.$refs.child.changeNumber (this.value += 1)
},
changeValue (value) {
this.value = +value
}
}
}
</script>
<!-- Child.vue -->
<template>
<input type="text" :value="number" @input="handleInput">
</template>
<script>
export default {
data () {
return {
number: 0
}
},
methods: {
handleInput (e) {
let number = e.target.value
this.$parent.changeValue(number?number:0);
},
changeNumber (value) {
this.number = value
}
}
}
</script>
EventBus(也叫发布订阅者模式)
适用于父子,隔代,兄弟组件通信
使用 EventBus 之前,需要在全局注册一个 EventBus 方法,这里我们将 EventBus 注册到 Vue 原型上。
// main.js
import Vue from 'vue'
Vue.prototype.$EventBus = new Vue()
实现一个兄弟组件通信
<!-- Parent.vue -->
<template>
<div>
<child1></child1>
<child2></child2>
</div>
</template>
<script>
import Child1 from "./Child1.vue";
import Child2 from "./Child2.vue"
export default {
components: {
Child1,
Child2
}
}
</script>
<!-- Child1.vue -->
<template>
<input type="text" @input="handleInput" placeholder="请输入内容">
</template>
<script>
export default {
methods: {
handleInput (e) {
this.$EventBus.$emit("handleShow", e.target.value);
}
}
}
</script>
<!-- Child2.vue -->
<template>
<p>{{text}}</p>
</template>
<script>
export default {
data () {
return {
text: ""
}
},
mounted () {
this.$EventBus.$on("handleShow", this.handleContent);
},
beforeDestroy() {
this.$EventBus.$off("handleShow", this.handleContent);
},
methods: {
handleContent (text) {
this.text = text;
}
}
}
</script>
在 Child1 组件中,通过 E v e n t B u s . EventBus. EventBus.emit 发射一个事件,在 Child2 兄弟组件中,通过 E v e n t B u s . EventBus. EventBus.on 接收事件,并且第二个参数传回调函数,拿到传递过来的数据,最后在 beforeDestroy 这个生命周期中,通过 E v e n t B u s . EventBus. EventBus.off销毁事件。
VueX
适用于父子,隔代,兄弟组件通信
使用 VueX 首先需要安装 VueX
npm install vuex
在main.js 引入 vuex
import VueX from 'vuex'
Vue.use(Vuex)
vuex 的核心
- state:用于保存数据
state: {
count: 0
}
- getter:用于修饰数据,在这里可以对 state 中的数据进行特殊修改
getters: {
getCount: state => state.count,
// 例如
sum: state => state.count + 10
}
- mutation:改变 state,通过 commit 提交 mutation 改变 state,mutation是唯一可以改变 store 状态的方式。
mutations: {
addCount: state => state.count++
}
mutation必须是同步函数
- action:异步的改变state操作,但是只能通过commit提交mutation来改变state,不能直接修改state,通过dispatch提交action操作。
actions: {
addCount ({commit}) {
setTimeout(() => commit('addCount') ,2000);
}
}
例子:
// main.js
const store = new Vuex.Store({
state: {
count: 0
},
getters: {
getCount: state => state.count,
sum: state => state.count + 10
},
mutations: {
addCountSync: state => state.count++
},
actions: {
addCount ({commit}) {
setTimeout(() => commit('addCountSync') ,2000);
}
}
});
new Vue({
...
store
})
<template>
<div>
<h1>{{count}}</h1>
<button @click="handleClickSync">同步改变count</button><br>
<button @click="handleClick">异步改变count</button>
</div>
</template>
<script>
export default {
computed: {
count () {
return this.$store.getters.getCount
}
},
methods: {
handleClickSync () {
this.$store.commit('addCountSync');
},
handleClick () {
this.$store.dispatch('addCount');
}
}
}
</script>
provide 和 inject
适用于隔代组件
// parent.vue
export default {
provide(){
return {
parentName: '我是父组件标题'
}
}
}
// child1.vue
export default {
inject: ['parentName']
}