面试官:如何使用Event Bus进行Vue组件间通讯?css
本身先想一分钟!html
译者注:英语和文笔有限,不对之处欢迎留言斧正!原文地址:css-tricks.com/using-event…vue
默认状况下,Vue组件间通讯使用的是 props。Props会将数据从父组件传递到子组件。例如,有个prop为 title
的组件:面试
<blog-post title="My journey with Vue"></blog-post>
复制代码
Props老是从父组件传到子组件。一旦你的应用程序变的愈来愈复杂,你就会明白所谓的 prop drilling 是什么意思了。这里有篇React相关的文章说的就是这个。prop drilling 是将 props 向下一级一级一级的传给本身子组件的作法 —— 这个过程你懂得!vuex
所以,繁琐的 prop drilling 可能会给系统带来潜在的问题(译者注:特别是数据追溯方面,一层一层的找挺麻烦)。话说回来了,父子组件咱们能够经过 props 传递,其余无关组件呢?固然经过 vuex、localstorage、session 等都是阔以的。但咱们今天要讲的是 Event Bus。微信
什么是 Event Bus 呢?正如它的名字同样,咱们能够将数据从一个组件送到另外一个组件,不管这些组件位于组件树中的哪一个位置。markdown
让咱们一块儿构建一些东西来演示一下 Event Bus 的概念。或许能够加值、减值以及计算总和的计数器是一个不错的开始。 掘金 markdown 不能嵌入 Codeopen。因此你能够狠狠的戳这里查看示例效果。 下面是截图: session
要使用 Event Bus,首先咱们须要有一辆车才行,来,初始化一个:app
import Vue from 'vue';
const eventBus = new Vue();
复制代码
其实就是 new 了一个 Vue 实例给了一个叫 eventBus
变量。这个变量你能够随意起名,只要你喜欢就好(译者注:国际惯例,通常都叫这个名字)。若是你使用的单文件组件 ,你须要把上面的代码片断放到单独的文件里,而后导出这个变量以便在其余地方使用:ide
import Vue from 'vue';
export const eventBus = new Vue();
复制代码
完成后,咱们就能够在咱们的计数器组件中使用它了。这里我列举了一些要作的功能清单:
下面是模板文件中的代码:
<div id="app">
<h2>Counter</h2>
<h2>{{ count }}</h2>
<input type="number" v-model="entry" />
<div class="div__buttons">
<button class="incrementButton" @click.prevent="handleIncrement">
Increment
</button>
<button class="decrementButton" @click.prevent="handleDecrement">
Decrement
</button>
</div>
<p>{{ text }}</p>
</div>
复制代码
输入框中绑定了 entry
属性,用来增长和减小计数,具体内容取决于用户的输入。单击任一按钮时,咱们会触发一个方法,该方法会增长或减小计数的值。最后,<p>
标签包含的 {{ text }}
内容是咱们打印的消息,显示咱们对计数器的操做。
下面是咱们 JavaScript 中的内容:
new Vue({
el: '#app',
data() {
return {
count: 0,
text: '',
entry: 0
}
},
created() {
eventBus.$on('count-incremented', () => {
this.text = `Count was increased`
setTimeout(() => {
this.text = '';
}, 3000);
})
eventBus.$on('count-decremented', () => {
this.text = `Count was decreased`
setTimeout(() => {
this.text = '';
}, 3000);
})
},
methods: {
handleIncrement() {
this.count += parseInt(this.entry, 10);
eventBus.$emit('count-incremented')
this.entry = 0;
},
handleDecrement() {
this.count -= parseInt(this.entry, 10);
eventBus.$emit('count-decremented')
this.entry = 0;
}
}
})
复制代码
经过查看上面的代码你已经注意到了,咱们已经跳到车上了,立刻发车!
咱们要作的第一件事就是创建一个从一个组件发送到另外一个组件的路。如何铺路呢?经过 eventBus.$emit()
(使用 emit 做为发送听起来挺花里胡哨)。eventBus.$emit
消息发送事件在两个方法中, handleIncrement
和 handleDecrement
,这俩方法监听用户输入后的提交操做,一旦他们被触发,咱们的 event bus 就会派发事件并开始在组件间发送数据。
你可能已经注意到了,咱们正在 created()
生命周期钩子中使用 eventBus.$on()
监听这两个事件。请注意,监听事件和发送事件的事件名必须保持一致。当 eventBus 识别出派发的事件名后,就会调用对应的监听函数 — 在监听函数中,咱们设置一个文原本显示咱们执行的操做,并使其3s后消失。
假设咱们正在开发一个我的资料页面,用户能够在这个页面更新本身的昵称和电子邮件,而后在不刷新页面的状况下查看更新。这个可使用 event bus 轻松完成,即使咱们此次处理的是两个组件:用户资料组件和修改资料提交表单组件。
示例代码戳这里,下面是截图:
这里是 html 代码:
<div class="container">
<!-- 我的资料 -->
<div id="profile">
<h2>Profile</h2>
<div>
<p>Name: {{name}}</p>
<p>Email: {{ email }}</p>
</div>
</div>
<!-- 修改资料表单-->
<div id="edit__profile">
<h2>Enter your details below:</h2>
<form @submit.prevent="handleSubmit">
<div class="form-field">
<label>Name:</label>
<input type="text" v-model="user.name" />
</div>
<div class="form-field">
<label>Email:</label>
<input type="text" v-model="user.email" />
</div>
<button>Submit</button>
</form>
</div>
</div>
复制代码
咱们将传递 ids
(user.name
和 user.email
)给相应的组件。首先,让咱们给修改我的资料(edit__profile
)组件设置模板。该组件包含咱们在 html 模板中绑定的属性。一样的,当提交事件触发后,咱们使用 eventBus 来派发事件,并传递表单数据。看下面的代码:
new Vue({
el: "#edit__profile",
data() {
return {
user: {
name: '',
email: ''
}
}
},
methods: {
handleSubmit() {
eventHub.$emit('form-submitted', this.user)
this.user = {}
}
}
})
复制代码
从修改资料表单中传递出来的数据将会应用在我的资料组件。也就是说,当公交车到站(监听到派发事件)后,就会接受到发送过来的数据(name
和 email
)从而实现页面更新。看下面的代码:
new Vue({
el: '#profile',
data() {
return {
name: '',
email: ''
}
},
created() {
eventHub.$on('form-submitted', ({ name, email}) => {
this.name = name;
this.email = email
})
}
})
复制代码
他们的口袋都装满了,如今他们要作的就是回家。
是否是很酷? 即使修改资料组件和我的资料展现组件并不相关 — 或不是直接的父子关系),他们也是能够相互通讯的,由于他们都坐同一班车。
在我设计响应式应用系统中我发现 Event Bus 确实很好用 — 特别是,当我基于服务端数据来更新组件时并不会形成页面刷新。并且,派发的事件能够同时被多个组件监听。
若是你有其余有趣的使用 Event Bus 的场景,欢迎留言。🚌
最后,下面是我维护的一个Q群,欢迎扫码进群哦,让咱们一块儿交流学习吧。也能够加我我的微信:G911214255 ,备注 掘金
便可。