面试的时候有点蒙,结束之后想想自己好像根本就误解了面试官的问题,因为我理解的这个问题本身就没有意义。但是当时已经有一些思路,但是在一个点上被卡住。
结束之后脑子瞬间灵光,想出了当时没有迈出的那一小步。所以不想计较这个问题本身的意义,单纯的想要把这个我理解错了的问题解决,就当是满足自己一个小小的愿望吧。
用 addEventListener() 和 attachEvent() 给一个 DOM 元素绑定事件处理程序时,如果传入一个匿名函数,那么用相应的 removeEventListener() 和 detachEvent() 是无法将这个匿名的处理程序解除绑定的。所以我们用的时候应该传入一个函数表达式。
那么,如果我就是想使用匿名函数进行绑定和解绑,怎么解决?
既然这两个函数都高冷的说明了不接受相同的匿名函数进行解绑,那么就只能另寻出路,不能靠它来管理事件了。
所以需要一个自定义的对象来管理事件。
事件处理程序的本质就是,当一个事件在一个对象上发生时,执行监听这个事件的函数。
翻译一下:
一个 DOM 元素可能被绑定多个事件类型的处理程序。比如 click 的时候颜色改变,mouseover 的时候变大。
一个事件类型可能绑定多个事件处理程序。比如 mouseover 的时候又变色又变大。
所以,这个事件对象应该有一个属性用来存储这个 DOM 元素上绑定的所有事件处理程序,还应该有两个方法,一个用来添加,一个用来删除。
- {
- handlers: {
- type1: [handler1, handler2],
- type2: [handler1, handler2],
- ... //其他事件类型和对应的事件处理函数
- },
- on: function() {},
- off: function() {}
- }
当一个事件发生时,就调用这个对象里面对应的事件类型的数组里面的所有函数。
所以绑定事件就是往对应的数组里面添加函数,解除绑定事件就是把这个函数从这个数组里面删掉。
那么怎么保证操作的是那个正确的 DOM 元素呢?
显然,每个 DOM 元素都应该需要一个这样的对象,用于管理自己的事件处理程序。
每个对象都有的东西,那不就是他的属性嘛。(而我当时就被卡在了这里)。
每个 DOM 元素都需要这样一个对象,而且每个对象中的 on() 和 off() 方法都是相同的,所以需要一个构造函数,把这两个方法放到他的原型对象中去。
- function EventManage() {
- this.handlers = {}
- }
- EventManage.prototype = {
- on: function(type, handler) {
- if (!this.handlers[type]) {
- this.handlers[type] = [handler];
- return true; //避免添加多个事件
- } else {
- this.handlers[type].push(handler);
- }
- },
- off: function(type, handler) {
- for (var i = 0,
- len = this.handlers[type].length; i) {
- if (this.handlers[type][i].toString() == handler.toString()) {
- this.handlers[type].splice(i, 1);
- }
- }
- }
- }
每个对象有了这两个方法,就可以自行添加和移除事件处理程序了,但是,监听事件,还是要靠 JavaScript 提供的方法,所以借用 addEventListner() 和 attachEvent() 来监听事件:
- var EventUtil = {};
- EventUtil.on = function(ele, type, handler) {
- if (!ele.event) {
- ele.event = new EventManage();
- }
- var isNewType = ele.event.on(type, handler);
- var fire = function() {
- for (var i = 0,
- len = ele.event.handlers[type].length; i) {
- ele.event.handlers[type][i]();
- }
- };
- if (isNewType) {
- if (ele.addEventListener) {
- ele.addEventListener(type, fire, false);
- } else {
- ele.attachEvent("on" + type, fire);
- }
- }
- }
- EventUtil.off = function(ele, type, handler) {
- ele.event.off(type, handler);
- }
这里要注意一个问题,每次使用 EventUtil.on() 时都会重新定义一个 fire 函数,addEventListener() 就会给相同的事件类型添加多个相同的事件处理程序,所以需要判断一下这个事件类型是不是新增的,如果是的话再用 addEventListener() 来监听这个事件类型。
- var btn = document.getElementById("btn");
- EventUtil.on(btn, "click",
- function() {
- console.log("11");
- });
- EventUtil.on(btn, "click",
- function() {
- console.log("22");
- });
- EventUtil.off(btn, "click",
- function() {
- console.log("11");
- });
当点击 btn 时,只打印了 "22",说明匿名函数成功解绑。
来源: http://www.cnblogs.com/LiveWithIt/p/6009824.html