vue组件化开发是一个非常美妙的过程,因为减少了代码之间的耦合度,提高了复用性,直接就是我们开发人员的福音。
但是组件归组件,组件之间也有几种不同的关系,不同的关系要有对应的通信方法才是道理,比如组件之间关系图就像是下面的一样,组件还不止这些,那这些复杂的组件通信应该怎么处理呢?
接下来我将介绍一下vue常见的两种种组件通信方式。
父子通信「props / $emit」
父传子
我想从父组件传一个数据给子组件,也就是上图的从app组件传到A组件,我可以先在App.vue组件定义一个数组,然后通过v-bind的方式绑定到子组件。
<template>
<div id="app">
<Child :ancient='ancient'/>
</div>
</template>
<script>
import Child from './views/Child.vue'
export default {
data () {
return {
ancient: ['床前明月光', '疑似地上霜', '举头望明月', '低头思故乡']
}
},
methods: {
},
components: {
Child
}
}
</script>
然后再在子组件通过props接收,然后循环渲染上去就好啦!
<template>
<div>
<ul>
<h2>静夜思</h2>
<h4>李白</h4>
<li v-for="item in ancient" :key="item">{{ item }}</li>
</ul>
</div>
</template>
<script>
export default {
props: {
ancient: {
type: Array,
required: true
}
},
data () {
return {
demoList: [111, 222, 333]
}
}
}
</script>
浏览器效果:
子传父
想在子组件传参数给父组件,首先我们在子组件创建一个点击事件,然后我们通过点击触发$emit事件将想要传递的值发送过去。
<template>
<div>
<input type="text" v-model="myText">
<button @click="handleClick">提交</button>
</div>
</template>
<script>
export default {
data () {
return {
myText: '请写出你的计划'
}
},
methods: {
handleClick () {
console.log(this.myText)
this.$emit('setMessage', this.myText)
this.myText = ''
}
}
}
</script>
然后我们在父组件通过on监听子组件的事件并接收传递过来的值然后再触发这边的事件,从而达到子传父的目的。
<template>
<div id="app">
<Child v-on:setMessage="getMessage"/>
<ul>
<li v-for="item in demoList" :key="item">{{item}}</li>
</ul>
</div>
</template>
<script>
import Child from './views/Child.vue'
export default {
data () {
return {
demoList: ['计划1', '计划2', '计划3']
}
},
methods: {
getMessage (text) {
this.demoList.push(text)
}
},
components: {
Child
}
}
</script>
浏览器如下表示:
兄弟通信
兄弟通信比较推荐用bus通信,因为可以直接两个组件之间互相通信从而省去了子传父再传子两个步骤。
首先先声明一辆bus,也就是在一个合适的地方创建一个EvenBus.js,然后内部如下:
import Vue from 'vue'
const eventBus = new Vue()
export default eventBus
然后有人可能会疑惑为什么要这样引入vue实例。先带着这个疑问继续看下去。
然后我将两个组件放在App组件内,分别是BroderB.vue和BroderD.vue。
APP.vue
<template>
<div id="app">
<BorderB />
<BorderD />
</div>
</template>
<script>
import BorderB from './views/BroderB.vue'
import BorderD from './views/BroderD.vue'
export default {
data () {
return {
}
},
methods: {
},
components: {
BorderB,
BorderD
}
}
</script>
然后我们先看BroderB.vue
<template>
<div>
<input type="text" v-model="myText">
<button @click="handleClick">提交</button>
</div>
</template>
<script>
import evenBus from '../util/EvenBus'
export default {
data () {
return {
myText: ''
}
},
methods: {
handleClick () {
evenBus.$emit('setMessage', this.myText)
}
}
}
</script>
我这里引入了EvenBus,然后通过点击事件触发事件,然后这里回应为什么要实例,因为每个实例都有emit 方法,当然也有监听 $on 方法。然后传递这个事件和值出去。
然后再在BroderD.vue接收
<template>
<div>
<h1 v-for="item in demoList" :key="item">{{item}}</h1>
</div>
</template>
<script>
import evenBus from '../util/EvenBus'
export default {
data () {
return {
demoList: ['111', '222', '333']
}
},
methods: {
handleGet (msg) {
this.demoList.push(msg)
}
},
mounted () {
evenBus.$on('setMessage', this.handleGet)
},
beforeDestroy () {
evenBus.$off('setMessage', this.handleGet)
}
}
</script>
在这个组件的mounted钩子函数中监听这个$on事件,并触发这里的方法,从而让两个组件产生通信,然后就是这里的方法接收值并使用值了
然后也有人会问,为什么后面还有一个beforeDestroy的钩子函数,那肯定是有作作用的,当我们结束这个组件的时候最好就是让这个evenBus解绑,因为如果在项目中的话,可能会存在某些奇奇怪怪的问题。
然后我们看浏览器如下