vue 组件通信
在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。 父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息。看看它们是怎么工作的。
父组件通过 prop 给子组件下发数据:
1Vue.component('child', {
2 // 在 JavaScript 中使用 camelCase
3 props: ['myMessage'],
4 template: '<span>{{ myMessage }}</span>'
5})
1<!-- 在 HTML 中使用 kebab-case -->
2<child my-message="hello!"></child>
子组件通过事件给父组件发送消息:
1<div id="message-event-example" class="demo">
2 <p v-for="msg in messages">{{ msg }}</p>
3 <button-message v-on:message="handleMessage"></button-message>
4 <!-- 使用 $on(eventName) 监听事件 -->
5</div>
1Vue.component('button-message', {
2 template: `<div>
3 <input type="text" v-model="message" />
4 <button v-on:click="handleSendMessage">Send</button>
5 </div>`,
6 data: function () {
7 return {
8 message: 'test message'
9 }
10 },
11 methods: {
12 handleSendMessage: function () {
13 this.$emit('message', { message: this.message }) // 使用 $emit(eventName, optionalPayload) 触发事件
14 }
15 }
16})
17
18new Vue({
19 el: '#message-event-example',
20 data: {
21 messages: []
22 },
23 methods: {
24 handleMessage: function (payload) {
25 this.messages.push(payload.message)
26 }
27 }
28})
非父子组件通信
有时候两个组件也需要通信(非父子关系)。在简单的场景下可是使用一个空的vue实例作为中央事件总线:
1let bus = new Vue()
1//触发组件 A 中的事件
2bus.$emit('is-selected', 1)
3``````js
4//在组件 B 创建的钩子中监听事件
5bus.$on('is-selected', function(id){
6
7})
这个集中式的事件中间件就是 Bus。可以将bus定义到全局: app.js
1var eventBus = {
2 install(Vue,options) {
3 Vue.prototype.$bus = vue
4 }
5};
6Vue.use(eventBus);
然后在组件中,可以使用$emit, $on, $off 分别来分发、监听、取消监听事件: 分发事件的组件
1// ...
2methods: {
3 todo: function () {
4 this.$bus.$emit('todoSth', params); //params是传递的参数
5 //...
6 }
7}
监听的组件
1// ...
2created() {
3 this.$bus.$on('todoSth', (params) => { //获取传递的参数并进行操作
4 //todo something
5 })
6},
7
8// 最好在组件销毁前
9// 清除事件监听
10beforeDestroy () {
11 this.$bus.$off('todoSth');
12},
如果需要监听多个组件,只需要更改 bus 的 eventName:
1// ...
2created() {
3 this.$bus.$on('firstTodo', this.firstTodo);
4 this.$bus.$on('secondTodo', this.secondTodo);
5},
6// 清除事件监听
7beforeDestroy () {
8 this.$bus.$off('firstTodo', this.firstTodo);
9 this.$bus.$off('secondTodo', this.secondTodo);
10},