我们知道,在JavaScript中,原生DOM事件在开发中是很有用的(与用户交互的重要方式),但是操作原生DOM事件其实有两大缺点:性能低、依赖于浏览器(NodeJs、小程序等不可用)。那么这个时候,就需要我们进行自定义事件去处理某些特定的业务。

认识Event对象及元素的dispatchEvent方法

在JavaScript中,所有事件的父对象就是Event对象,也就是说像我们平时所有的点击(click)、触摸(touch)、鼠标等事件对象都继承自Event。理解这一点是很重要的。先来简单看一个事件的场景。

场景一、页面上有两个按钮a、b,当点击按钮b的时候,调用按钮a的点击事件。简单布局代码如下:

<button id="btn1">a</button>
<button id="btn2">b</button>

程序员A的做法,分别获取这两个按钮,然后给b按钮添加点击事件后,调用按钮a的click方法。代码如下:

<button id="btn1" onclick="alert('I am a button named a')">a</button>
<button id="btn2">b</button>
<script>
let btn1 = document.querySelector('#btn1');
let btn2 = document.querySelector('#btn2');
btn2.onclick = function(){
btn1.onclick();
}
</script>

程序员B的做法,分别获取这两个按钮,然后给b按钮添加点击事件后,在回调函数中在添加按钮a的点击事件。代码如下:

<button id="btn1">a</button>
<button id="btn2">b</button>
<script>
let btn1 = document.querySelector('#btn1');
let btn2 = document.querySelector('#btn2');
btn2.onclick = function(){
btn1.addEventListener('click',function(){
alert('I am a button named a')
},false)
}
</script>

看到这里,你认为谁的做法是正确的?显然程序员A的做法是对的(就目前的要求来看),但有缺陷,如果按钮a的事件是通过addEventListener方法去注册监听的,就不起作用了。那么该怎样做才会比较好?这就需要我们的Event对象和元素的dispatchEvent方法了。改进代码如下:

<button id="btn1">a</button>
<button id="btn2">b</button>
<script>
let btn1 = document.querySelector('#btn1');
let btn2 = document.querySelector('#btn2');
btn1.addEventListener('click',function(){
alert('I am a button named a')
},false)
btn2.onclick = function(){
let ev = new Event('click');
btn1.dispatchEvent(ev);
}
</script>

其中:

  • Event对象的构造函数需要一个参数,事件类型
  • dispatchEvent方法是将某个事件分发给某个元素

认识自定义事件

前面说过,在浏览器端javascript中,所有的事件都继承自Event,那么其实要想实现一个自定义事件,也是需要继承自Event。

还是类似上面说过的场景,场景二:有两个按钮a,b,当调用b按钮的点击事件,怎么去触发a按钮上的自定义事件?

<button id="btn1">a</button>
<button id="btn2">b</button>
<script>
let a = document.querySelector('#btn1');
let b = document.querySelector('#btn2');
a.addEventListener('myClick',function(){
alert('I am a button named a')
},false)
class MyEvent extends Event{
constructor(...args){
super(...args);
this.a = 12;
}
}
b.onclick = function(){
const ev = new MyEvent('myClick');
a.dispatchEvent(ev);
}
</script>

这就是自定义事件的思想体现

  • 根据事件类型进行事件的注册
  • 根据事件的类型分发对应的事件给需要者

可以看出,对事件进行管理是很有必要,如Java中的EventBus、VueJs中的、emit等,将事件的监听者及分发者抽象成一个独立的模块,来进行事件的管理(添加、移除等)有利用解耦。

事件队列完成组件间的通信

这里可以把事件队列想象成一根管道,类似前端gulp实现的核心思想(基于管道)、当使用者需要使用某个事件的时候,就在管道中注册一个事件,然后通过该事件的类型,从管道中分发一个该类型的事件,在不需要使用后,还可以对相应的事件进行移除操作。代码如下:

class Pipe{
constructor(){
this.pipes = {};
}
/**
* 注册事件
* @param {*} type
* @param {*} fn
*/
on(type,fn){
this.pipes[type] = this.pipes[type] || [];
if(this.pipes[type].findIndex(func => func==fn)==-1){
this.pipes[type].push(fn);
}
}
/**
* 移除事件
* @param {*} type
* @param {*} fn
*/
off(type,fn){
if(this.pipes[type]){
this.pipes[type] = this.pipes[type].filter((func) => func!==fn); if(this.pipes[type].length===0){
delete this.pipes[type];
}
}
}
/**
* 分发事件
* @param {*} type
* @param {...any} args
*/
emit(type,...args){
if(this.pipes[type]){
this.pipes[type].forEach((fn) => {
fn(...args);
})
}
}
}

场景:通过事件队列模拟vuejs中组件间通信的实现。Component1负责对数据进行渲染,Component2中点击按钮,来改变Component1实例属性a的值。代码如下:

 
<div id="box">
{{a}}
</div>
<button id="btn1">++</button>
<script>
const $ = document.querySelectorAll.bind(document);
let pipe = new Pipe();
class Component1{
constructor(){
this.a = 12;
this.el = $("#box")[0];
this.render();
pipe.on('add',(arg) => {
this.a+=arg;
this.render();
})
} render(){
this.el.innerHTML = this.a;
}
} class Component2{
constructor(){
this.el = $("#btn1")[0];
this.el.onclick = function(){
pipe.emit('add',12);
}
}
} new Component1();
new Component2();
</script>

转发至:https://segmentfault.com/a/1190000020550517?utm_source=tag-newes

利用JavaScript自定义事件完成组件间的数据通信的更多相关文章

  1. Javascript事件模型系列(四)我所理解的javascript自定义事件

    被我拖延了将近一个月的javascript事件模型系列终于迎来了第四篇,也是我计划中的最后一篇,说来太惭愧了,本来计划一到两个星期写完的,谁知中间遇到了很多事情,公司的个人的,搞的自己心烦意乱浮躁了一 ...

  2. 理解的javascript自定义事件

    理解的javascript自定义事件 被我拖延了将近一个月的javascript事件模型系列终于迎来了第四篇,也是我计划中的最后一篇,说来太惭愧了,本来计划一到两个星期写完的,谁知中间遇到了很多事情, ...

  3. Javascript自定义事件功能与用法实例分析

    原文地址:https://www.jb51.net/article/127776.htm 本文实例讲述了javascript自定义事件功能与用法.分享给大家供大家参考,具体如下: 概述 自定义事件很难 ...

  4. javascript:自定义事件初探

    javascript:自定义事件初探   http://www.cnblogs.com/jeffwongishandsome/archive/2008/10/27/1317148.html

  5. javascript 自定义事件 发布-订阅 模式 Event

    * javascript自定义事件 var myEvent = document.createEvent("Event"); myEvent.initEvent("myE ...

  6. vuejs单一事件管理组件间的通信

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. 高级功能:很有用的javascript自定义事件

    之前写了篇文章<原生javascript实现类似jquery on方法的行为监听>比较浅显,能够简单的使用场景. 这里的自定义事件指的是区别javascript默认的与DOM交互的事件,比 ...

  8. JavaScript自定义事件,动态添加属性

    根据事件的不同,可用的自定义方法也不同. document.createEvent('Event'); 实现主要有4个步骤: 1.创建事件. 2.初始化事件(三个参数:事件名,是否起泡,是否取消默认触 ...

  9. vue自定义事件 子组件把数据传出去

    每个 Vue 实例都实现了事件接口(Events interface),即: 使用 $on(eventName) 监听事件 使用 $emit(eventName) 触发事件 1.使用v-on绑定自定义 ...

  10. JavaScript自定义事件

    很多DOM对象都有原生的事件支持,向div就有click.mouseover等事件,事件机制可以为类的设计带来很大的灵活性,相信.net程序员深有体会.随着web技术发展,使用JavaScript自定 ...

随机推荐

  1. normal matrix 正规矩阵

    资料来源 In mathematics, a complex square matrix A is normal if   满足此条件也意味着A可对角化. 所以,厄米矩阵和幺正矩阵都是正规矩阵.

  2. 2-2 C++变量

    目录 2.2.1 变量定义:列表初始化(list initialization) 2.2.2 变量的定义与声明 C++分离式编译 定义与声明 2.2.3 C++变量命名 2.2.4 变量名的作用域(s ...

  3. GoLang协程Goroutiney原理与GMP模型详解

    本文原文地址:GoLang协程Goroutiney原理与GMP模型详解 什么是goroutine Goroutine是Go语言中的一种轻量级线程,也成为协程,由Go运行时管理.它是Go语言并发编程的核 ...

  4. 2023NOIP A层联测28 T3 大眼鸹猫

    2023NOIP A层联测28 T3 大眼鸹猫 比赛做出来了,但是文抄-- 思路 分析每一个 \(i\),发现其一定需要上升或下降 \(|a_i-b_i|\). 如果求出最小操作次数,然后在此基础上, ...

  5. 鸿蒙NEXT开发案例:二维码的生成与识别

    [引言] 在本篇文章中,我们将探讨如何在鸿蒙NEXT平台上实现二维码的生成与识别功能.通过使用ArkUI组件库和相关的媒体库,我们将创建一个简单的应用程序,用户可以生成二维码并扫描识别. [环境准备] ...

  6. Redis究竟为什么这么快?

    Redis为什么这么快? 完全基于内存,数据存在内存中,绝大部分请求是纯粹的内存操作,非常快速,跟传统的磁盘文件数据存储相比,避免了通过磁盘IO读取到内存这部分的开销. 数据结构简单,对数据操作也简单 ...

  7. 关于switch的优化:转移表(完结)

    用转移表来代替功能实现中的 switch 语句 1. switch 语句应用场景 在许多场景中会用到条件判断,此时简单的条件判断一般通过 if/else 语句实现:如果涉及三条以上的功能分支一般会通过 ...

  8. 解析Mina代码三部曲

    首先,Mina是什么?能帮我们做什么?我研究一个新技术的时候,首先问的就是这样的问题.我个人的理解就是Mina是一个关注于通讯层的框架,任何需要底层通讯的应用,都可以使用它. AD:2013大数据全球 ...

  9. 通过su - userName 切换用户,无法通过userdel -r 删除用户?

    需要通过exit退出用户,su只是进行了切换,并没有关闭

  10. groovy 内存回收测试

    问题 在使用我们的开发平台时,客户怀疑我们的动态执行脚本会导致系统内存回收的问题,导致系统不响应,为此我专门针对这个问题,做一下详细的测试,看看是不是到底有什么影响. 测试步骤 1.使用编写一个控制器 ...