mitt tiny-emitter发布订阅应用场景源码解析

mitt tiny-emitter发布订阅应用场景源码解析

简介

mitt是一个基于JavaScript的简单、快速、可扩展的发布/订阅(pub/sub)库,适用于各种应用场景。它的基本思想是订阅者向一个发布者注册其感兴趣的事件类型,当该类型事件发生时,订阅者会被通知并执行其所定义的响应逻辑。这种解耦合的模式为开发者提供了良好的可维护性和扩展性。

mitt的实现采用了只有500多个字节的精简代码,同时它还具有优雅和易用的API,因此备受广大开发者的喜爱。本文将对mitt的应用场景和源码进行详细介绍,并通过两个具体示例进行说明。

应用场景

mitt适用于各种应用场景,主要包括以下几个方面:

  • 事件代理:mitt可以用于事件代理,即将子组件通知/通信的事件发送到它们的父组件。这样可以很好地解耦,方便组件系统的维护和扩展。
  • 状态管理:mitt可以用于状态管理,即当状态改变时,它可以通知所有与之相关的订阅者,从而实现组件之间的协作、同步和响应。
  • 异步/回调处理:mitt可以用于异步/回调处理,即在异步/回调方法中使用mitt来处理完成事件,从而在异步操作完成后进行相应的处理。

源码解析

下面是mitt的源码解析。首先是mitt的主体代码:

export default function mitt(all = Object.create(null)) {
  return {
    /**
     * Register an event handler for the given type.
     *
     * @param  {string} type    Type of the event to listen for, or `"*"` for all events
     * @param  {Function} handler Function to call in response to the given event
     * @memberOf mitt
     */
    on(type, handler) {
      (all[type] || (all[type] = [])).push(handler);
    },

    /**
     * Remove an event handler for the given type.
     *
     * @param  {string} type    Type of the event to unregister `handler` from, or `"*"`
     * @param  {Function} handler Handler function to remove
     * @memberOf mitt
     */
    off(type, handler) {
      if (all[type]) {
        all[type].splice(all[type].indexOf(handler) >>> 0, 1);
      }
    },

    /**
     * Invoke all handlers for the given type.
     * If present, `"*"` handlers are invoked after type-matched handlers.
     *
     * @param {string} type The event type to invoke
     * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
     * @memberOf mitt
     */
    emit(type, evt) {
      (all[type] || []).slice().map((handler) => { handler(evt); });
      (all['*'] || []).slice().map((handler) => { handler(type, evt); });
    }
  };
}

mitt函数接收一个名为all的对象作为参数,它用来存储事件类型和其对应的处理函数。具体的实现中,all使用Object.create(null)生成,它是一个全新的、空的对象,没有原型链的干扰。

mitt函数返回一个带有3个方法的对象,分别为onoffemit

  • on(type, handler):用于为指定类型的事件注册一个处理函数。
  • off(type, handler):用于删除指定类型的事件的处理函数。
  • emit(type, evt):用于触发指定类型的事件,并可传递相关数据。

下面是对每个方法的具体实现进行说明:

on(type, handler)

这个方法用于注册事件处理函数。它接收两个参数,分别为事件类型和处理函数。如果事件类型已经存在,则在其对应的处理函数数组中添加新处理函数;如果事件类型不存在,则创建新的处理函数数组,添加处理函数并保存至all对象中。代码如下:

(all[type] || (all[type] = [])).push(handler);

要注意的是,这里有一个判断条件(all[type] || (all[type] = [])),如果all对象没有type属性,那么就会将其初始化为一个空数组。

off(type, handler)

这个方法用于删除事件处理函数。它接收两个参数,分别为事件类型和处理函数。如果事件类型的处理函数数组存在,且其中包含指定的处理函数,则将其从数组中删除。代码如下:

if (all[type]) {
  all[type].splice(all[type].indexOf(handler) >>> 0, 1);
}

要注意的是,这里使用了位运算符>>>,它的作用是将其后面的数字转换为无符号32位整数。如果不使用位运算符,则在处理器函数未找到时,其返回值为-1,会导致数组删除失效。

emit(type, evt)

这个方法用于触发指定类型的事件。它接收两个参数,分别为事件类型和传递给事件处理函数的数据。首先,它将all对象中记录的该事件类型的所有处理函数复制到一个新数组中,然后依次执行每一个数组元素的处理函数。代码如下:

(all[type] || []).slice().map((handler) => { handler(evt); });

其次,如果存在all对象的'*'属性,则将包含在'*'中的处理函数也添加到新数组中。代码如下:

(all['*'] || []).slice().map((handler) => { handler(type, evt); });

这样,所有处理函数都将被执行,而且'*'中的处理函数将排在普通类型处理函数的后面。

示例说明

示例1:组件通信

Vue组件中使用mitt实现子组件向父组件通信。

<template>
  <div>
    <Child @notify="onNotify"></Child>
    <p v-if="message">{{ message }}</p>
  </div>
</template>

<script>
import mitt from 'mitt';
const emitter = mitt();

export default {
  data() {
    return {
      message: ''
    };
  },
  methods: {
    onNotify(data) {
      this.message = data;
    }
  },
  mounted() {
    emitter.on('notify', this.onNotify);
  },
  beforeDestroy() {
    emitter.off('notify', this.onNotify);
  }
};
</script>

在子组件中,我们可以通过emitter.emit('notify', data)将数据传递到父组件中。

<template>
  <button @click="onClick">点击通知</button>
</template>

<script>
import mitt from 'mitt';
const emitter = mitt();

export default {
  methods: {
    onClick() {
      // 通知父组件
      emitter.emit('notify', 'Hello, Parent Component!');
    }
  }
};
</script>

示例2:异步回调处理

通过mitt来处理异步方法的回调,例如Vue官方提供的$http方法。

// 使用Vue
this.$http.get('api/data').then((res) => {
  emitter.emit('data', res.data);
});

// 注册处理函数
emitter.on('data', (data) => {
  // 处理数据
});

或者使用其他HTTP库。

// 使用axios
axios.get('api/data').then((res) => {
  emitter.emit('data', res.data);
});

// 注册处理函数
emitter.on('data', (data) => {
  // 处理数据
});

这样,在异步操作完成后,我们就可以通过emit方法同步数据,实现逻辑的处理。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:mitt tiny-emitter发布订阅应用场景源码解析 - Python技术站

(0)
上一篇 2023年5月28日
下一篇 2023年5月28日

相关文章

  • Vue组件基础用法详解

    下面我将详细讲解“Vue组件基础用法详解”的完整攻略。 一、Vue组件基础 在Vue中,组件是可复用的Vue实例。它们接受相同的选项(例如,data,computed,mounted),并且可以有自己的模板,方法, 以及样式。组件系统提供了一种抽象,让我们可以使用独立可复用的小组件构建大型应用程序。 二、全局注册组件 全局注册一个组件,需要使用Vue.com…

    Vue 2023年5月27日
    00
  • vue el-switch初始值(默认值)不能正确显示状态问题及解决

    Vue el-switch初始值不能正确显示状态问题及解决攻略 问题描述: vue使用element UI库中的switch组件时,如果设置了默认值,可能会出现初始状态无法正确显示的问题。 问题分析: 这个问题的原因是因为element UI中的switch并没有提供v-model来绑定value值,而是提供了v-model来绑定一个boolean值,也就是…

    Vue 2023年5月27日
    00
  • vue双击事件2.0事件监听(点击-双击-鼠标事件)和事件修饰符操作

    下面就给您详细讲解一下“Vue双击事件2.0事件监听(点击-双击-鼠标事件)和事件修饰符操作”的完整攻略。 什么是Vue双击事件2.0事件监听 Vue双击事件是指在Vue框架中注册的鼠标单击事件,在间隔一定时间后再次点击鼠标,使其触发双击事件的一种事件处理方式。在Vue 2.0版本中,双击事件具有更高的可定制性和可扩展性。 点击事件 在Vue中,可以通过 v…

    Vue 2023年5月29日
    00
  • vue中的 $slot 获取插槽的节点实例

    当我们在Vue中使用插槽(slot)时,通常我们只是将DOM或组件插入到插槽中,以实现一些定制化展示或行为。然而,有时候我们需要获取插槽中的DOM或组件实例,比如在父组件中获取插槽中子组件的某个方法或属性。此时,$slot这个神奇的属性就派上用场了。 什么是$slot? $slot是Vue 2.6.0版本中新加入的一个特殊的属性,它是在2.5版本新增的$sc…

    Vue 2023年5月28日
    00
  • Vue项目开发常见问题和解决方案总结

    下面是关于“Vue项目开发常见问题和解决方案总结”的完整攻略: 一、项目搭建 1. Vue CLI版本升级 在开发过程中,可能会遇到Vue CLI版本不兼容等问题,需要进行版本升级。可以使用以下命令进行升级: npm update -g @vue/cli 2. 安装Vue.js相关依赖 在项目初始化时,需要安装Vue.js相关依赖。这里推荐使用npm包管理工…

    Vue 2023年5月28日
    00
  • 手把手教你如何开发属于自己的一款小程序

    “手把手教你如何开发属于自己的一款小程序” 一、准备工作 1. 注册小程序账号 在开发小程序前,首先需要在微信公众平台上注册小程序账号。 2. 安装开发工具 微信官方提供了小程序开发工具,可在官网下载并安装:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html 3. 创…

    Vue 2023年5月28日
    00
  • Vue配置环境变量的正确打开方式

    Vue是一种流行的JavaScript前端框架,它提供了许多强大的功能和工具帮助我们在开发前端应用时更加高效和方便。在Vue开发中,我们通常需要使用一些环境变量来配置不同环境的API地址、端口号、代理设置等等。这篇攻略将会为大家详细介绍在Vue中,如何配置环境变量的正确打开方式。 步骤一:在项目根目录下添加.env文件 首先,我们需要在Vue项目的根目录下添…

    Vue 2023年5月28日
    00
  • Element实现表格嵌套、多个表格共用一个表头的方法

    当需要在Element框架中实现表格嵌套或多个表格共用一个表头时,可以采用以下两种方法: 方法一:使用 render 函数自定义表格中每一列的渲染方式 示例如下: <template> <el-table :data="tableData"> <el-table-column prop="name&…

    Vue 2023年5月29日
    00
合作推广
合作推广
分享本页
返回顶部