Vue组件通信方式全面详解

vue组件通信方式全面详解

众所周知,Vue主要思想就是组件化开发。因为,在实际的项目开发中,肯定会以组件的开发模式进行。形如页面和页面之间需要通信一样,Vue 组件和组件之间肯定也需要互通有无、共享状态。接下来,我们就悉数给大家展示所有 Vue 组件之间的通信方式

组件关系

Vue组件通信方式全面详解

App组件和A组件、A组件和B组件、B组件和C组件形成父子关系

B组件和D组件形成兄弟关系

App组件和C组件、App和B组件形成了隔代关系(其中的层级可能是多级,既隔多代)

组件通信

这么多的组件关系,那么组件和组件之间又有哪些通信的方式呢?各种方式的区别又是什么?适用场景又是什么呢?

props和$emit

这种方式是我们日常开发中应用最多的一种方式。

props以单向数据流的形式可以很好的完成父子组件的通信

所谓单向数据流:就是数据只能通过 props 由父组件流向子组件,而子组件并不能通过修改 props 传过来的数据修改父组件的相应状态。至于为什么这样做,Vue 官网做出了解释:

**所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

正因为这个特性,于是就有了对应的 $emit。$emit 用来触发当前实例上的事件。对此,我们可以在父组件自定义一个处理接受变化状态的逻辑,然后在子组件中如若相关的状态改变时,就触发父组件的逻辑处理事件。

let Child = { template: `<div> <input type="text" v-model='msg'/> <button @click='handleClick'>传递</button> </div>`, props: ['msg'], methods: { handleClick() { this.$emit('getChildData', '子组件数据') } }, } let Parent = { data() { return { msg: '小马哥', val:'' } }, methods: { getChildData(val) { this.val = val; } }, template: ` <div> <p>我是一个父组件</p> <p>我是{{val}}</p> <Child :msg='msg' @getChildData='getChildData'></Child> </div> `, components: { Child } } let vm = new Vue({ el: '#app', template: ` <div> <Parent></Parent> </div> `, components: { Parent } })

父传子:父组件传递msg数据给子组件,通过v-bind绑定msg,子组件中直接可以用props接收绑定的数据

子传父:子组件触发相应的事件,通过$emit触发事件传递数据,父组件中绑定对应的事件,通过$on监听对应的事件 接收子组件传递的数据

EventBus-中央事件总线

如果想实现兄弟组件之间进行通信,在项目规模不大的情况下,完全可以使用中央事件总线EventBus的方式。如果你的项目规模是大中型的,那我们会使用vuex状态管理

EventBus通过新建一个Vue事件bus对象,通过bus.$emit触发事件,bus.$on监听触发的事件。

Vue.component('A', { template: ` <div> <p>我是A组件</p> <button @click='handleClick'>A传递到B</button> </div> `, data() { return { msg: 'hello 小马哥' } }, methods: { handleClick() { this.$bus.$emit('globalEvent',this.msg); } }, }) Vue.component('B', { template: ` <div> <p>我是B组件</p> <h3>{{aValue}}</h3> </div> `, data() { return { aValue: '' } }, created () { this.$bus.$on('globalEvent',(val)=>{ this.aValue = val; }) }, }) // 定义中央事件总线 let bus = new Vue(); // 将中央事件总线赋值给Vue.prototype中,这样所有组件都能访问到了 Vue.prototype.$bus = bus; let vm = new Vue({ el: '#app', template: ` <div> <A></A> <B></B> </div> `, }) $attrs和$listeners

通过 props进行组件通信的方式只适合直接的父子组件,如果父组件A下面有子组件B,组件B下面有组件C,这时如果组件A直接想传递数据给组件C那就行不通了! 只能是组件A通过 props 将数据传给组件B,然后组件B获取到组件A 传递过来的数据后再通过 props 将数据传给组件C。当然这种方式是非常复杂的,无关组件中的逻辑业务一种增多了,代码维护也没变得困难,再加上如果嵌套的层级越多逻辑也复杂,无关代码越多!

针对这样一个问题,Vue 2.4提供了$attrs 和$listeners来实现能够直接让组件A传递消息给组件C

Vue.component('A', { template: ` <div> <p>我是A组件</p> <B :msg='msg' @getCData='getCData'></B> </div> `, methods: { getCData(val) { alert(val) } }, data() { return { msg: 'hello 小马哥' } }, }) Vue.component('B', { template: ` <div> <p>我是B组件</p> <!-- C组件中能直接触发 getCData 的原因在于:B组件调用 C组件时,使用 v-on 绑定了 $listeners 属性 --> <!-- 通过v-bind 绑定 $attrs 属性,C组件可以直接获取到 A组件中传递下来的 props(除了 B组件中 props声明的) --> <C v-bind='$attrs' v-on='$listeners'></C> </div> `, // props: ['msg'], data() { return { } } }) Vue.component('C', { template: ` <div> <p>我是C组件</p> <p>{{$attrs.msg}}</p> <button @click='handleClick'>传递数据</button> </div> `, methods: { handleClick() { this.$emit('getCData', 'C组件的数据') } }, data() { return { } } }) let vm = new Vue({ el: '#app', template: ` <div> <A></A> </div> `, })

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzgdj.html