使用Mitt替代EventBus
2021-10-18
本文介绍了如何在Vue3项目中使用Mitt库替代EventBus,通过安装、导入和使用Mitt实现组件间的事件传递。
Mitt
Mitt是一个体积极小的第三方消息发布/订阅式JavaScript库
官方文档是与框架无关的,所以这个玩意其实React、Vue都可以用
本文以Vue3为例,介绍Mitt库的导入和使用
安装
在项目的根目录下执行:
$ npm i mitt --save
导入
在 src/
下新建一个 bus.js
文件,内容如下:
/* bus.js */
import mitt from "mitt";
const bus = {}
const emitter = mitt()
bus.$on = emitter.on
bus.$off = emitter.off
bus.$emit = emitter.emit
export default bus
这段代码引入了mitt,并利用mitt()构造器生成了一个emit实例,同时把 on
、off
和 emit
方法赋值给了空对象 bus
,作为静态方法
打开 src/main.js
内容如下:
/* main.js */
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
改造 main.js
,导入刚才的 bus
对象,并挂载到全局
改造后的 main.js
:
/* main.js */
import { createApp } from 'vue'
import App from './App.vue'
import bus from './bus'
const app = createApp(App)
app.config.globalProperties.$bus = bus
app.mount('#app')
使用
这里,我们在父、子组件间通过刚才挂载的全局对象 $bus
来进行事件传递,并使用Vue3新增的 reactive
来实现一个响应式组件
改造
改造默认模板里的 src/App.vue
和 src/components/HelloWorld.vue
,改造后的 App.vue
:
<template>
<img alt="Vue logo" src="./assets/logo.png">
<button>这是一个按钮</button>
<HelloWorld msg="Welcome to Your Vue.js App"/>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
},
methods: {
handleClick() {
this.$bus.$emit('click')
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
改造后的 HelloWorld.vue
:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br/>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener"
>vue-cli documentation</a
>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li v-for="i in links" :key="i.text">
<a href={{i.link}} target="_blank" rel="noopener">{{ i.text }}</a>
</li>
</ul>
<h3>Essential Links</h3>
<ul>
<li>
<a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a>
</li>
<li>
<a href="https://forum.vuejs.org" target="_blank" rel="noopener"
>Forum</a
>
</li>
<li>
<a href="https://chat.vuejs.org" target="_blank" rel="noopener"
>Community Chat</a
>
</li>
<li>
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener"
>Twitter</a
>
</li>
<li>
<a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a>
</li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li>
<a href="https://router.vuejs.org" target="_blank" rel="noopener"
>vue-router</a
>
</li>
<li>
<a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a>
</li>
<li>
<a
href="https://github.com/vuejs/vue-devtools#vue-devtools"
target="_blank"
rel="noopener"
>vue-devtools</a
>
</li>
<li>
<a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener"
>vue-loader</a
>
</li>
<li>
<a
href="https://github.com/vuejs/awesome-vue"
target="_blank"
rel="noopener"
>awesome-vue</a
>
</li>
</ul>
</div>
</template>
<script>
import {reactive} from "vue";
export default {
name: "HelloWorld",
props: {
msg: String,
},
setup() {
const links = reactive([
{link: 'https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel', text: 'babel'},
{link: 'https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint', text: 'eslint'}
])
const add = () => links.push({
link: 'https://github.com/developit/mitt',
text: 'mitt'
})
return {links, add}
},
mounted() {
this.$bus.$on("click", this.add);
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>