Vue 非父子组件通信

前面的话

在实际业务中,除了父子通信外,还有很多非父子组件通信的场景,非父子组件一般有两种,兄弟组件和跨多级组件。Vue.js 2.x中,使用一个空的Vue实例作为中央事件总线(bus)。
中央事件总线就好比一个中介,租房者与出租者担任两个跨级组件,租房者与出租者之间的联系全靠中介,而两个跨级组件之间的通信全靠中央事件总线(bus)。

中央事件总线
<div id="app1">
        <component-a></component-a>
        <component-b></component-b>
</div>
<script>
  var bus = new Vue();
    var app1 = new Vue({
        el: '#app1',
        components: {
            'component-a': {
                template:  `
                <p>{{message}}{{changeMsg}}</p>
                `,
                data() {
                    return {
                        message: ''
                    }
                },
                computed:{
                  changeMsg() {
                    var that = this;
                    // 监听来自bus实例的事件
                    bus.$on('on-message',function(msg) {
                    that.message = msg;
                })
                }
                } 
            },
            'component-b': {
                template: `
                <button @click="handleEvent">传递事件</button>
                `,
                methods: {
                    handleEvent: function() {
                        // 点击按钮通过bus把事件on-message发出去
                        bus.$emit('on-message','来自组件component-b的内容')
                    }
                }
            }
        }
     
    });
</script>

上例中组件component-a与component-b是兄弟关系: 首先创建了一个名为bus的空实例,作为中央事件总线。然后创建了 Vue实例app1, 局部定义了两个兄弟组件,在component-b组件中,点击按钮会通过bus把事件on-message发出去;在 component-a中用监听属性监听来自bus实例的事件。
在这里插入图片描述
在这里插入图片描述
除了中央事件bus外,还有两种方法可以实现组件间通信:父链与子组件索引.

父链

在子组件中,使用this.$ parent可以直接访问该组件的父实例或组件,父组件也可以通过this.$children访问它的所有 的子组件,而且可以递归向上或向下无线访问,直到根实例或最内层的组件。

  <div id="app2">
        <parent-component></parent-component>
   </div>
  <script>
 var childNode = {
        template: `
            <button @click="handleEvent">通过父链直接修改数据</button>
        `,
        methods: {
            handleEvent() {
                // 访问父链后,可以做任何操作,比如直接修改数据
                this.$parent.message = '来自组件child-component的内容'
            }
        }
    }
    var app2 = new Vue({
        el:'#app2',
        components: {
            'parent-component': {
                template:   `
                    <div class="parent">
                    <p>{{message}}</p>
                    <child-component></child-component>
                    </div>
                `,
                data() {
                    return {
                        message: ''
                    }
                },
                components:  {
                    'child-component': childNode
                }
            }
        }
    });
</script>

在这里插入图片描述
在这里插入图片描述
尽管Vue允许这样操作,但是在业务中,子组件应该尽可能避免依赖父组件的数据,更不该去修改它的数据,这样 使得父子组件紧耦合,父组件可以被任意组件修改,理想情况下,只有组件自己能修改它的状态。父子组件最好 还是通过props和$emit来通信。

子组件索引

当子组件较多时,通过this.children来一一遍历出我们需要的一个组件实例是比较困难的,尤其是组件动态渲染时,它们的序列是不固定的。Vue提供子组件索引的方法,用特殊的属性ref来为子组件指定一个索引名称。

    <div id="app3">
        <parent-component></parent-component>
    </div>
    <script>
 var app3 = new Vue({
        el:'#app3',
        components: {
            'parent-component': {
                template: `
                    <div class="parent">
                        <button @click="handleRef">通过ref获取子组件实例</button>
                        <child-component ref="childCom"></child-component>
                    </div>
                `,
                components: {
                    'child-component':  {
                        template: `
                            <div>子组件</div>
                        `,
                        data(){
                            return {
                                message: '子组件的内容'
                            }
                        }
                    }
                },
                methods: {
                    handleRef() {
                        // 父组件通过$ref来访问指定的实例
                        var msg = this.$refs.childCom.message;
                        console.log(msg);
                    }
                }
            }
        }
    })
</script>

在父组件模板中,子组件标签上使用ref指定一个名称,并在父组件内通过this.$refs来访问指定名称的子组件。

注意:$refs只在组件渲染完成后才填充,并且时非响应式的。它仅仅作为一个直接访问子组件的应急方案,应当避免在模板或计算属性中使用 $ refs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值