可以先看例子
从 js 自定义事件 里知道:元素A通过dispatchEvent方法触发的事件,只有A上注册的监听器才能监听得到。
我们想要的效果是,别的对象干了某件事之后, 发个消息给我们,好让我们能做相应的改变。要做到这样,也不是没办法:我们可以在一个公共对象上监听和触发事件,这就很有意义了。
例子一:通知多个对象
要实现 元素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);
});
注意:import
进来的变量虽然不使用,但是一定不能省略
文件b.js
:
var b = document.getElementById("b");
document.addEventListener("clickA",function(e){b.innerHTML = "(128,345)";
})
文件c.js
:
var c = document.getElementById("c");
document.addEventListener("clickA",function(e){c.innerHTML = "你点了A";
})
这样写,三个模块之间完全不用关心对象,也不知道对方存在,耦合度非常的低,完全可以独立编写,不会互相影响。这其实就是一个观察者模式的实现。
例子二:游戏框架
要开发一个游戏,启动游戏,加载图片和音乐,加载完后,渲染场景和音效,加载和渲染由不同的人负责。可以这样写:
文件: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"));
})
文件:loadImage.js
// 加载图片
document.addEventListener("gameStart",function(){console.log("加载图片...");setTimeout(function(){console.log("加载图片完成");document.dispatchEvent(new Event("loadImageSuccess"));},1000);});
文件:loadMusic.js
//加载音乐
document.addEventListener("gameStart",function(){console.log("加载音乐...");setTimeout(function(){console.log("加载音乐完成");document.dispatchEvent(new Event("loadMusicSuccess"));},2000);});
文件: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)
});
加载模块和渲染模块互不影响,易于扩展。
携带信息
除此之外,事件还能传递自定义信息:
var event = new CustomEvent('myEvent', { 'dataName': dataContent });document.dispatchEvent(event);
(注意:传递自定义信息需要使用CustomEvent
,而不是Event
)
然后在监听函数里取出:
document.addEventListener("myEvent",function(e){console.log(e.dataName);
})
这个功能非常有用!
使用自定义事件的优缺点
优点: 各模块之间低耦合
缺点:不好定位问题,容易导致诡秘的错误。曾在一个项目上用到自定义事件,大体如下:
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);
})
你会发现得到一个很怪异的结果,仅仅是多加一句,整个程序的流程就完完全全的改变了,而且很难定位问题。
要解决这种问题,好好的打印日志或许是一个办法。