0.前言
写这篇文章的主要原因是,看到很多手写evntbus的文章和发布npm包的文章,
但是没有把两者结合在一起的,于是想要写一篇放在一起的文章,这样就实现了一个完整的写工具,到发布工具,到使用工具的整个流程.
本文最后实现的发布包链接如下:
www.npmjs.com/package/eas…
1.概念
1.1eventbus
eventbus即事件总线,是一种利用发布/订阅者模式进行组件间通信的方式.
在EventBus的应用中,不同组件可以订阅事件,也可以发布事件。当一个事件发生时,所有订阅了这个事件的组件都会接收到这个事件,并可以做出相应的处理。
- 以下是一个简单的使用例子:
// 发布信息的组件
import EventBus from './event-bus.js'; // 导入EventBus
EventBus.emit('eventName', 'hello')
// 订阅信息的组件
import EventBus from './event-bus.js'; // 导入EventBus
EventBus.on('eventName', (data) => {
console.log(data)
})
1.2npm包
npm相信大家都不会陌生,而且是非常熟悉,我们项目下载依赖和运行命令时会用到,类似Python的pip命令.
npm全称是Node Package Manager即node包管理,是nodejs默认包管理工具,我们安装nodejs时就会同时安装npm.
npm官网有着丰富的软件包可以满足你的大部分需求www.npmjs.com
但是如果我们发现没有合适的软件包,于是自己实现了一个功能,想要发布到npm网站上,以便自己以后下载或者给其他开发者使用呢?
那么怎么实现npm发布包呢?别急下面我来教会你
2.实现
2.1 手写eventbus
eventbus的基本api有on(订阅),emit(发布),once(触发一次订阅后销毁),off(移除回调监听),reset(清除所有订阅)
是不是感觉有点多,有点望而却步?别怕,这里我们先实现核心的订阅on和发布emit事件
2.1.1先搭个框架
首先明确我们的需求:
-
1).实现一个eventbus
-
2).实现eventbus的发布事件emit
-
3).实现eventbus的订阅事件on
明确需求后,我们最好先打个框架,就像写作文先写大纲后面写起来就不慌不忙,心中有数一样,写需求先写个框架,也让咱们程序员心中有底,更好完成任务 (方便更好摸鱼,这个划掉)
首先新建一个EventBus函数,再在EventBus函数内部,新建一个on函数和一个emit函数,然后在EventBus函数最后返回on和emit函数
function EventBus() {
function on() {
}
function emit() {
}
return {
on, emit
}
}
2.1.2实现eventbus中的订阅事件on
这里我们先要实现的是eventbus中的订阅事件on,
诶这里可能有同学就要问了,为什么不先先写发布事件emit呢?实际使用不是我们先emit一个事件,然后再使用on来接收事件吗?按顺序不是应该先写emit事件吗?
其实没啥为什么,先写emit也可以,硬要解释的话,可以这样理解:
实际触发事件时,先触发emit事件,然后调用对应on事件的回调函数,在emit事件之前,我们要进行订阅on,告诉eventbus订阅对应的事件和触发的回调,这样emit事件触发时,才能通知对应的事件和回调.
还是难以理解吗?我来举个外卖的栗子:
我现在很饿,想点一份华莱士蜜汁手扒鸡
昨天刚吃,我打开美团外卖,下单(菜品:蜜汁手扒鸡,地址:翻斗花园7栋1208),
这就相当于订阅事件on,事件名是蜜汁手扒鸡,回调是送到翻斗花园7栋2208,
等到店家的蜜汁手扒鸡做好后,交给骑手,骑手查看该订单对应的地址送货上门,
这就相当于发布事件emit,蜜汁手扒鸡做好触发emit事件,然后骑手查询该事件(蜜汁手扒鸡)对应的回调(送货地址),执行回调(送货上门)
简单来说就是先下单后配送,不下单想白嫖吗?
具体实现如下:
-
1).建立一个事件池,存储键值对:事件名eventName和对应的回调数组callbacks(因为同一个事件,触发的回调有很多,所以放入数组中)
-
2).订阅事件on,传入两个参数,分别是事件名eventName和回调函数callback,
-
3).根据传入事件名eventName查询是否已经存在该事件的回调数组,没有则新建回调数组
-
4).把传入的回调函数callback加入上一步获取的回调数组callbacks
-
5).更新事件池,即在事件池中存入事件和新的回调数组
// 事件池
const events = new Map();
function EventBus() {
// 订阅事件
function on(eventName, callback) {
// 1.获取对应事件回调数组,没有则新建
const callbacks = events.get(eventName) || new Set();
// 2.把新回调加入回调数组
callbacks.add(callback);
// 3.更新事件池
events.set(eventName, callbacks);
}
function emit() {
}
return {
on, emit
}
}
2.1.3实现eventbus中的发布事件emit
emit发布事件就比较简单了,传入事件名和参数,调用对应的回调即可
具体实现如下:
-
1).emit发布事件,传入事件名和参数
-
2).根据事件名获取对应事件回调数组
-
3).数组为空则抛出错误,数组存在则执行数组中每个回调并传入参数
const events = new Map();
function EventBus() {
function on(eventName, callback) {
const callbacks = events.get(eventName) || new Set();
callbacks.add(callback);
events.set(eventName, callbacks);
}
// 发布事件
function emit(eventName, payload) {
// 1.获取对应事件回调数组
const a = events.get(eventName);
// 2.数组为空则抛出错误,数组存在则执行数组中每个回调并传入参数
if (!a) throw new Error('事件不存在');
a.forEach(fn => fn(payload));
}
return {
on, emit
}
}
2.1.4 全部代码
const events = new Map();
function EventBus() {
function on(eventName, callback) {
const callbacks = events.get(eventName) || new Set();
callbacks.add(callback);
events.set(eventName, callbacks);
}
function emit(eventName, payload) {
const a = events.get(eventName);
if (!a) throw new Error('事件不存在');
a.forEach(fn => fn(payload));
}
return {
on, emit
}
}
export default EventBus();
2.2 发布npm包
2.2.1 注册npm账号
注册:
登录:
登录成功如下:
2.2.2 建立发包文件夹
- 1).新建一个文件夹easyer-eventbus
- 2).使用vscode打开该文件夹在终端执行
npm init
初始化package.json
基本往下按回车即可,主要是设置包名,版本号,描述,入口文件,关键词,执行命令,git地址,作者,协议等
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (easyer-eventbus)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author: fwy
license: (ISC)
About to write to E:\桌面\easyer-eventbus\package.json:
{
"name": "easyer-eventbus",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"author": "fwy",
"license": "ISC"
}
- 3). 在package.json同级目录下新建index.js把步骤2.1.4 的全部代码复制到这里,这个就是我们的入口文件
2.2.3 发布npm包
- 1).npm确认为npm原始源
如果是淘宝源或其他源改为npm源
// 查看npm镜像源地址
npm config get registry
// 设置npm默认源
npm config set registry https://registry.npmjs.org/
- 2).在命令行上登录npm
npm login
按步骤输入用户名,密码和邮箱的一次性密码
- 注意:
- 在这里输入密码不会显示出来,这是没问题的,输入完点回车即可
- 邮箱的一次性密码需要登录注册npm时的邮箱查看
登录成功如下:
- 3).npm发布
npm publish
- 注意:发布前请到npm官网查询是否已经有相同名字的包,如果重名则发布不成功,改一个没被使用的包名即可
发布成功如下:
3.查询及测试
3.1 到官网查询刚才发布的包
查询成功!!!
恭喜恭喜!!!到这里你成功学会了简单手写eventbus和发布npm包了,从此你就踏上了自己造轮子的征程,一颗前端新星正在冉冉升起
如果你还有精力的话可以继续往下看
3.2 测试使用
发布成功后,还需要测试一下,我们的包能否正常下载和使用:
3.2.1.能否使用npm i 下载
- 打开之前的一个前端项目,随意打开一个即可,有package.json即可
先切换为淘宝镜像源
npm config set registry https://registry.npm.taobao.org/
执行下载命令
npm i easyer-eventbus
下载成功如下:
查看package.json
3.2.2.eventbus能否使用
我这里直接使用我的之前的vue项目来测试
父组件app.vue
点击按钮发布信息
<script setup lang="ts">
import test from "./pages/test.vue";
// @ts-ignore
import eventbus from "easyer-eventbus"
const emit = () => {
eventbus.emit("test", "hello world !!")
}
</script>
<template>
<test></test>
<h1 @click=emit>发布信息</h1>
</template>
<style scoped></style>
子组件test.vue
在父组件点击按钮后text内容变化
<script setup lang="ts">
// @ts-ignore
import eventbus from "easyer-eventbus"
import { ref } from "vue";
const text = ref('test')
eventbus.on("test", (data) => {
console.log(data);
text.value = data
})
</script>
<template>
<h1> {{ text }}</h1>
</template>
<style scoped></style>
初始状态:
预期状态:点击发布信息后如果 test 文字变为 hello world !! ,那么eventbus就是能够正常使用的
- 打包后的eventbus可以正常使用
4.总结
本文实现了两个模块,一个是手写简单eventbus,另一个是发布npm包.并进行了下载测试.