2

当组件监听到用户的行为,需要触发一些界面交互的时候,实例与组件之间、组件相互之间就需要进行通信了。Vue里面有两个api可以帮助我们轻松地完成这件事,它们是$on$emit

实例和组件(parent child)之间的通信

先来看一下我们最后要完成的效果吧。初始状态:
final-1

点击按钮以后隐藏文字:
final-2

初始代码

<div id="app">
    <div class="boxWrapper">
        <div>I am your Big Box</div>
    </div>
    <toggle-btn></toggle-btn>
</div>
Vue.component('toggle-btn', {
    template: '<button class="btn btn-info">Toggle Box</button>'
})

var app = new Vue({
    el: '#app'
})

我们把按钮做成一个简单的组件,那应该怎么获取按钮监听到的点击事件,传给big box呢?

监听按钮组件上的自定义事件

用户点击的时候,是在toggle-btn这个组件上触发了事件,所以我们信号的源头,肯定是在它身上。Vue允许我们监听组件上的自定义事件,像这样:

<toggle-btn v-on:toggle-box="toggleBox"></toggle-btn>

这里有几点需要注意的:

  • 自定义的事件,需要用中划线分词,在HTML和JS都是。用驼峰分词是完全没有效果的。

  • 虽然监听的是组件的自定义事件,但后面触发的这个toggleBox方法,是在Vue实例上的。

  • 这里是监听的是自定义的事件,真正的click事件,是在组件内部进行监听(下面会解释)。

所以上面的这行HTML的意思,其实是,当Vue实例监听到组件上自定义的toggle-box事件被触发,就会执行它的toggleBox方法。

组件发布信号

被监听的事件有了,这个组件到底要怎么把信号发布出来,让Vue实例监听到呢?我们直接来看下面这段代码。

在组件的内部监听到用户的click事件后,执行自身的方法,把信号发布出去。

Vue.component('toggle-btn', {
    template: '\
        <button \
            class="btn btn-info" \
            v-on:click="emmitToggle">Toggle Box</button>\
    ',
    methods: {
        emmitToggle: function() {
            // 用户点击之后,发布信号
            this.$emit('toggle-box')
        }
    }
})

完善事件触发的方法

接收到信号以后,我们希望可以toggle文字的显示,最直接的当然是在实例上的data里面初始化一个showBoxtrue,执行toggleBox方法的时候对它进行操作。同时,big box里面的文字通过v-show指令来控制是否显示。

<div class="boxWrapper">
    <div v-show="showBox">I am your Big Box</div>
</div>
var app = new Vue({
    el: '#app',
    data: {
        showBox: true
    },
    methods: {
        toggleBox: function() {
            this.showBox = !this.showBox
        }
    }
})

完整的通信流程

  • 组件监听用户行为(我们的例子里是点击)

  • 用户点击,触发组件自身的方法并发布信号($emit):我这边的toggle-box事件被触发了

  • HTML中的v-on指令捕捉到这个信号,执行Vue实例下的toggleBox方法

  • showBox的值被修改,v-show对文字进行隐藏或显示

组件之间的通信

其实$emit方法是挂在Vue实例下,每一个Vue实例都会有$emit$on方法。所以可以直接把vue实例作为一个event bus,在组件之间进行通信。

这里简单地举个例子。比方说,我们希望点击toggle按钮以后,另外一个组件可以接收到这个信号。

toggle-btn基本不变,只是改为使用event bus的$emit方法。listener中也同样使用event bus的$on对信号进行监听。

<div id="app">
    <listener></listener>
    <toggle-btn></toggle-btn>
</div>
var bus = new Vue()

Vue.component('toggle-btn', {
    template: '\
        <button \
            class="btn btn-info" \
            v-on:click="emmitToggle">Toggle Box</button>\
    ',
    methods: {
        emmitToggle: function() {
            // 注意这里使用的是bus,不是this
            bus.$emit('toggle-box')
        }
    }
})

Vue.component('listener', {
    template: '<h5>sibling component</h5>',
    mounted: function () {
        bus.$on('toggle-box', function () {
            alert('已经接收到toggle-box信号!')
        })
    }
})

var app = new Vue({
    el: '#app'
})

sibling-com

写在最后

源码地址:https://github.com/levblanc/v...

视频攻略:小的不才,为求一赞,自制 本期视频攻略 在此。


留白shiye
256 声望65 粉丝