所谓跨元件,即是两个元件并无父子关系,并没有被对方包着。如果要互相传递资料,可以使用 mitt(在 Vue 2 是 event bus)、Vuex 或 route props 来处理。
Event bus 和 Mitt 的原理是一样,假设现在有两个元件,A 元件和 B 元件。我想把 A 元件的资料传给 B 元件,步骤就是:
on
来注册监听该事件off
把该监听移除接下来这几天,我会为以上每种方法,各自写一篇解说文章。此篇文章会集中讨论 mitt 与 eventbus。
先讲解 Vue 2 的 eventbus 用法,因为懂了 eventbus 自然就会懂得用 mitt。注意,event bus 已经不能在 Vue 3 里使用,因为 Vue 3 已移除 $on
、$off
、 $once
语法, 而 eventbus 需要使用 $on
来监听 $emit
发出的事件,因此没有 $on
的话,就无法用 event bus 的方法。
稍为重温这些语法:
$on
:注册监听$off
:销毁监听$once
:只监听一次$emit
:发出事件首先建立一个 event bus,之後我们会使用此 event bus 来监听事件和触发事件。建立 event bus 的常见做法有两种,择一即可:
第一种做法,就在 main.js 建立 event bus:
Vue.prototype.$bus = new Vue();
Vue.prototype
的语法是在 Vue 实体新增一个属性。属性前需要有 $
符号,这是官方提倡的一个写法,用作标示这个属性能够在所有元件里使用,同时避免与任何 data, computed 和 methods 的资料命名产生冲突。
第二种做法,就是直接另外建立新的 Vue 实体,把它当作 event bus。例如我在之後的示范例子中,会建立一个名为 eventBus.js 的档案,并建立新的 Vue 实体。
eventBus.js
import Vue from "vue";
export const EventBus = new Vue();
如果是前者,在任何元件里使用 event bus 时,只需要写 this.$bus
来使用。後者就需要先把 event bus import
进来才可以使用:
import { EventBus } from "@/eventBus";
EventBus.$on(...);
$on
建立监听事件,$emit
触发事件假设现在有以下情景:
有两个同阶层的元件,Button.vue
和 Message.vue
,当我按下 Button.vue
的按钮时,就会把在 Button.vue
的资料,传送给 Message.vue
,Message.vue
会负责把资料显示出来。
做法就是:
Button.vue
绑上 emit,当用户按按钮,就触发 emit 来发出事件,并把资料一并带出去。Message.vue
监听 Button.vue
所发出的事件,当事件从 Button.vue
发出时,就接收资料,并把它塞到 data,再把它显示出来。Button.vue:
<template>
<button type="button" @click="sendMessage">send message</button>
</template>
import { EventBus } from "@/eventBus";
export default {
data() {
return {
message: "Hello Vue!",
};
},
methods: {
sendMessage() {
// 发出 click-send-msg 事件,并把 message 当作参数传出去
EventBus.$emit("click-send-msg", this.message);
},
},
};
Message.vue:
<template>
<p>Button 传来的 Message: {{ msg }}</p>
</template>
<script>
import { EventBus } from "@/eventBus";
export default {
data() {
return {
msg: "",
};
},
mounted() {
// 监听事件
EventBus.$on("click-send-msg", (msgdata) => (this.msg = msgdata));
},
};
</script>
$off
移除监听当元件被销毁时,建议在 beforeDestroy
hook 里把此元件用到的监听事件移除,保持网页的效能。以下会再详细解释当中原因。
https://codesandbox.io/s/vue-2-event-bus-shi-fan-ewj4i?file=/src/components/Message.vue
这是因为当元件被销毁,在此元件使用 event bus 所注册的 event bus 监听事件并不会随之而消失。 更可怕的情况是,假设有两个元件同时监听同一个事件,即使其中一个元件被销毁,剩下一个元件,但当该元件侦测到该事件时被触发时,结果是网页会发出两个事件,不是一个。这是因为前一个被销毁的元件仍然残留监听事件。
在此附上此文章提出的此例子。明显示范了如果没有移除监听事件的话,会出现两个问题:
建议大家把程序码复制贴上到编辑器,以及使用本地 live server 预览跑一次,一边打开 console 和 memory 去看记忆体来理解作者的意思。
此例子所示范的情况是:
count
的数量来决定渲染多少个 BigTextComponent
。BigTextComponent
。BigTextComponent
在 created
hook 里,都会产生一笔极长的阵列,模拟资料量很大。同时,此元件会监听由 event 按钮发出的事件,当它发出事件时,就会跑 console.log('QQ iDontKnow')
。BigTextComponent
所监听的事件 ('myEvent')。如果我们不主动使用 $bus.$off('myEvent', this.eventHandler);
来移除元件的监听,即使按下 minus 按钮来销毁元件,还是会残留这些元件的监听,造成以上提到的两个问题:
console.log('QQ iDontKnow')
因此,需要主动在元件加入移除监视事件的程序码来解决问题。
Vue 3 的 mitt 跟以上提到 Vue 2 所使用的 event bus 几乎是一样。不同的是,mitt 是一个插件,需要事先载入,就是因为 Vue 3 移除了 $on
和 $off
语法,因此要依赖 mitt 此插件来完成。
做法跟以上的步骤一样,同样是注册监听事件和建立触发事件,在此就不再重复解说,直接分享完整的程序码示范:
https://codesandbox.io/s/vue-3-mitt-shi-fan-ox46v?file=/src/main.js
补充一点,Vue 3 建议使用 beforeUnmount
,而非 beforeDestroy
。
$on
注册监听事件,同时在另一个元件使用 $emit
来触发事件。beforeDestroy
(Vue 2)或 beforeUnmount
(Vue 3)移除监听事件,保持网页效能。How To Create a Global Event Bus in Vue 2
Vue3 中使用 Event Bus
Vue event bus 介绍
[Vue] Event Bus 是什麽? 怎麽用?
Data Pass Between Components using EventBus in Vue 3
<<: Day 7:225. Implement Stack using Queues
>>: Day 0x14 UVa10035 Primary Arithmetic
再来说样板template,样板只有参数型态不一样其余都相同(包括程序逻辑),样板基本上与写一般的函...
大家跟Large是否有点熟呀~~~就什麽大什麽大的嘛~~~ 喂~~但这里说的是Excel,作者呀~...
以下笔记摘录自『 The Go Workshop 』。 如果遇到需要一大堆if叙述才能处理的状况,就...
前言 前面两篇文章学习了 Struct 和 Class, 两者用法相同、功能相似, 都可以用来储存 ...
Introduce 为了API的安全性,本次跟各位介绍透过JWT Token来帮API做身分验证,简...