javascript自定义事件(可联系vue angular的eventbus或者叫中间人模式)

假如我们想要的效果是,别的对象干了某件事之后, 发个消息给我们,好让我们能做相应的改变。要做到这样,也不是没办法:我们可以在一个公共对象上监听和触发事件,这就很有意义了。


一:通知多个对象

要实现 元素A点击之后,元素B显示鼠标的位置,元素C显示提示,可以这样写:

文件:a.js

import b from "./b"
import c from "./c"

var a = document.getElementById("a");
a.addEventListener("click",function(e){
    var clickA = new Event("clickA");
    document.dispatchEvent(clickA);
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

注意:import进来的变量虽然不使用,但是一定不能省略

文件b.js:

var b = document.getElementById("b");
document.addEventListener("clickA",function(e){
    b.innerHTML = "(128,345)";
})
  • 1
  • 2
  • 3
  • 4
  • 5

文件c.js:

var c = document.getElementById("c");
document.addEventListener("clickA",function(e){
    c.innerHTML = "你点了A";
})
  • 1
  • 2
  • 3
  • 4

这样写,三个模块之间完全不用关心对象,也不知道对方存在,耦合度非常的低,完全可以独立编写,不会互相影响。这其实就是一个观察者模式的实现。


例子二:游戏框架

要开发一个游戏,启动游戏,加载图片和音乐,加载完后,渲染场景和音效,加载和渲染由不同的人负责。可以这样写:

文件:index.js

import loadImage from "./loadImage"
import loadMusic from "./loadMusic"
import initScene from "./initScene"   

var start = document.getElementById("start");
start.addEventListener("click",function(e){
    console.log("游戏开始!");
    document.dispatchEvent(new Event("gameStart"));
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

文件:loadImage.js

// 加载图片
document.addEventListener("gameStart",function(){
    console.log("加载图片...");

    setTimeout(function(){
        console.log("加载图片完成");
        document.dispatchEvent(new Event("loadImageSuccess"));
    },1000);

});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

文件:loadMusic.js

//加载音乐
document.addEventListener("gameStart",function(){
    console.log("加载音乐...");
    setTimeout(function(){
        console.log("加载音乐完成");
        document.dispatchEvent(new Event("loadMusicSuccess"));
    },2000);

});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

文件:initScene.js

//渲染场景
document.addEventListener("loadImageSuccess",function(e){
    console.log("使用图片创建场景...");
    setTimeout(function(){
        console.log("创建场景完成");
    },2000)
});

//渲染音效
document.addEventListener("loadMusicSuccess",function(e){
    console.log("使用音乐创建音效...");
    setTimeout(function(){
        console.log("创建音效完成");
    },500)
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

加载模块和渲染模块互不影响,易于扩展。


携带信息

除此之外,事件还能传递自定义信息

var event = new CustomEvent('myEvent', { 'dataName': dataContent });

document.dispatchEvent(event);
  • 1
  • 2
  • 3
  • 4

(注意:传递自定义信息需要使用CustomEvent,而不是Event

然后在监听函数里取出:

document.addEventListener("myEvent",function(e){
    console.log(e.dataName);
})
  • 1
  • 2
  • 3

这个功能非常有用!

使用自定义事件的优缺点

优点: 各模块之间低耦合

缺点:不好定位问题,容易导致诡秘的错误。曾在一个项目上用到自定义事件,大体如下:

let i = 0;
document.addEventListener("EventA",function(){
   i++;
   document.dispatchEvent(new Event("EventB"));
})

document.addEventListener("EventB",function(){
    i++;
    document.dispatchEvent(new Event("EventA")); //这句是不小心多加的 
    if(true){
       document.dispatchEvent(new Event("EventC"));
    }
})

document.addEventListener("EventC",function(){
   i++;
   console.log("i的值是:",i);
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

你会发现得到一个很怪异的结果,仅仅是多加一句,整个程序的流程就完完全全的改变了,而且很难定位问题。

猜你喜欢

转载自blog.csdn.net/baidu_31333625/article/details/79932110
今日推荐