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

yizhihongxing

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中使用装饰器。 什么是装饰器 装饰器是一种特殊的语法,可以修改类或者类中的方法。它本质上是一个函数,接受一个类或者类中的方法作为参数,返回修改后的类或者方法。在ES7中,装饰器的提案已经被纳入到正式规范中。 Vue中使用装饰器的方法 Vue中可以使用装饰器来装饰…

    Vue 2023年5月28日
    00
  • element vue Array数组和Map对象的添加与删除操作

    下面是关于Element Vue中Array数组和Map对象的添加和删除操作的完整攻略。 Array数组的添加和删除 添加元素 向数组中添加元素可以使用原生的Javascript方法push()、unshift(),也可以使用Vue的$set()方法。 首先,我们创建一个数组arr,然后使用push()和unshift()方法添加元素。 <script…

    Vue 2023年5月28日
    00
  • vue父组件与子组件之间的数据交互方式详解

    Vue父组件与子组件之间的数据交互方式详解 介绍 Vue是一款流行的前端框架,它提供了一种组件化的开发方式来构建Web应用程序。Vue的组件化开发方式具有很高的灵活性和可重用性,但是在组件化开发中,如何进行组件之间的数据交互是一件非常重要的事情。本文将介绍Vue父组件与子组件之间的数据交互方式。 父组件向子组件传递数据 父组件向子组件传递数据的方式有两种:p…

    Vue 2023年5月28日
    00
  • vant实现购物车功能

    下面是详细讲解 “vant 实现购物车功能” 的完整攻略: 概述 vant 是一套移动端的 Vue 组件库,它提供了丰富的 UI 布局和组件,包括轮播图、列表、按钮、输入框、弹出框等等常用的移动端组件,同时 vant 还提供了一些实用的 API,比如下拉刷新、无限滚动等等。vant 的组件库精简实用,特别适合开发移动端应用,本文将使用 vant 组件库来实现…

    Vue 2023年5月27日
    00
  • Vue3+Vite+TS实现二次封装element-plus业务组件sfasga

    下面是详细讲解 “Vue3 + Vite + TS 实现二次封装 element-plus 业务组件”的完整攻略。 一、前言 我们这里使用的框架是 Vue3,构建工具是 Vite,使用 TypeScript 对代码进行静态类型检查。我们将使用 element-plus 作为 UI 组件,同时对其进行二次封装。这样可以使我们的业务组件更加灵活、易用、容易扩展。…

    Vue 2023年5月27日
    00
  • vue深入解析之render function code详解

    我来为您详细讲解“Vue深入解析之Render Function Code详解”的攻略。 什么是Render Function Code? Render Function Code是指Vue中通过JavaScript编写的模板渲染函数。它可以方便地生成HTML标记,并且可以支持复杂的组件和动态渲染。Render Function Code对于深入理解Vue的…

    Vue 2023年5月28日
    00
  • 你知道Vue中神奇的$set是如何实现的吗?

    当你使用Vue的时候,可能会遇到一种情况:当向一个已经定义好的Vue实例中给不存在的属性赋值时,这个属性不会自动响应式地更新视图。这是因为Vue在实例化时只对已经存在的属性设置了响应式,如果后续添加了新的属性,就需要手动调用$set去设置响应式。 $set实现的原理是通过调用对象的defineReactive()方法,将新增的属性动态转换成getter/se…

    Vue 2023年5月29日
    00
  • Vue computed实现原理深入讲解

    首先我们来了解一下Vue computed属性的作用。 Vue中的computed属性是用于监听依赖变化并进行缓存的属性,其返回值会被缓存,只有当其依赖的属性发生变化时,才会重新计算并返回新值。这样可以避免反复重复计算已经得出的结果。 那么,Vue computed实现原理究竟是什么呢? 首先,我们需要了解computed属性的初始化时机。在Vue实例挂载后…

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