JavaScript 自定义事件(二)——Dom事件

上一次,了解了JS自定义事件。今天在DOM上进行事件方法扩展。

1.基于DOM扩展自定义方法(了解即可)

我们一起来添加一个addEvent方法

if (window.HTMLElement) {
    // 使用原型扩展DOM自定义事件
    
    HTMLElement.prototype.addEvent = function(type, fn, capture) {
        var el = this;
        if (window.addEventListener) {
            el.addEventListener(type, function(e) {
                fn.call(el, e);
            }, capture);
        } else if (window.attachEvent) {
            el.attachEvent("on" + type, function(e) {
                fn.call(el, e);
            });
        } 
    };
} else {
    // 如果是不支持HTMLElement扩展的浏览器
    // 通过遍历所有元素扩展DOM事件
    
    var elAll = document.all, lenAll = elAll.length;
    for (var iAll=0; iAll

HTMLElement 接口表示所有的 HTML 元素(nodeType==1)。以一个

标签元素举例,其向上寻找原型对象用过会是这样:HTMLParagraphElement.prototype → HTMLElement.prototype → Element.prototype → Node.prototype → Object.prototype → null。上述代码HTMLElement直接换成Element也是可以的,但是会让其他元素(例如文本元素等)也扩展addEvent方法,有些浪费了。

通过上面的扩展,element上就有了addEvent()方法。我们可以像下面展示的那样使用

这是pattyzzh的领地
document.getElementById("content-wrap").addEvent("click", function() { alert("欢迎光临pattyzzh"); });

基于DOM扩展缺点有:缺少标准无规律、提高冲突可能性、性能以及浏览器支持。扩展名字任意命,很有可能就会与未来DOM浏览器本身支持的方法相互冲突;扩展无规律,很有可能出现A和B同名不同功能的扩展而造成冲突;IE6-7浏览器下所有扩展都要通过遍历支持,其性能开销可想而知;另外IE8对DOM扩展的支持并不完整,例如其支持Element.prototype,却没有HTMLElement.prototype.


2.伪DOM自定义事件

这里的“伪DOM自定义事件”是自己定义的一个名词,用来区分DOM自定义事件的。例如jQuery库,其是基于包装器(一个包含DOM元素的中间层)扩展事件的,既与DOM相关,又不直接是DOM,因此,称之为“伪DOM自定义事件”。

如果只考虑事件添加,我们的工作其实很简单,根据支持情况,addEventListener与attachEvent方法分别添加事件即可:

addEvent: function(type, fn,  capture) {
    var el = this.el;
    if (window.addEventListener) {
        el.addEventListener(type, fn, capture);        
    } else if (window.attachEvent) {
        el.attachEvent("on" + type, fn);
    }
    return this;
}

自定义事件添加容易,但是如何触发它们呢?——考虑到自定义事件与浏览器行为无关,同时浏览器没有直接的触发事件的方法。

自定义事件的触发
  1. 对于标准浏览器,其提供了可供元素触发的方法:element.dispatchEvent()。不过,在使用该方法之前,我们还需要做其他两件事,及创建和初始化。因此,总结说来就是:
document.createEvent()
event.initEvent()
element.dispatchEvent()

createEvent()方法返回新创建的Event对象,支持一个参数,表示事件类型

JavaScript 自定义事件(二)——Dom事件_第1张图片
para.png

initEvent()方法用于初始化通过DocumentEvent接口创建的Event的值。支持三个参数:initEvent(eventName, canBubble, preventDefault). 分别表示 事件名称是否可以冒泡是否阻止事件的默认操作
dispatchEvent(eventObj)就是触发执行了.
举个例子

$(dom).addEvent("sayHello", function() {
alert("Hello");
});

// 创建
var event = document.createEvent("HTMLEvents");
// 初始化
event.initEvent("sayHello",true, false);
// 触发, 即弹出文字
dom.dispatchEvent(event);
  1. 对于IE浏览器,由于向下很多版本的浏览器都不支持document.createEvent()方法)。IE浏览器有不少自给自足的东西,例如下面要说的这个"propertychange"事件,顾名思义,就是属性改变即触发的事件。例如文本框value值改变,或是元素id改变,或是绑定的事件改变等等。
    当我们添加自定义事件的时候,顺便给元素添加一个自定义属性即可。例如,我们添加自定义名为"sayHello"的自定义事件,顺便我们可以对元素做点小手脚:
    dom.listener = 0;
    再顺便把自定义事件fn塞到"propertychange"事件中:
dom.attachEvent("onpropertychange", function(e) {
    if (e.propertyName == "listener") {
        fn.call(this);   //fn是事件处理函数
    }
});

这个,当我们需要触发自定义事件的时候,只要修改DOM上自定义的listener属性的值即可:
dom.listener = Math.random(); // 值变成随机数
此时就会触发dom上绑定的onpropertychange事件,又因为修改的属性名正好是"listener", 于是自定义的fn就会被执行。这就是IE浏览器下事件触发实现的完整机制。

自定义事件的删除

与触发事件不同,事件删除,各个浏览器都提供了对于的时间删除方法,如removeEventListener和detachEvent。不过呢,对于IE浏览器,还要多删除一个事件,就是为了实现触发功能额外增加的onpropertychange事件:
dom.detachEvent("onpropertychange", event);

综合
var $ = function(el) {
    return new _$(el);    
};
var _$ = function(el) {
    this.el = (el && el.nodeType == 1)? el: document;
};
_$.prototype = {
    constructor: _$,
    addEvent: function(type, fn, capture) {
        var el = this.el;
        if (window.addEventListener) {
            el.addEventListener(type, fn, capture);
            var ev = document.createEvent("HTMLEvents");
            ev.initEvent(type, capture || false, false);
            
            if (!el["ev" + type]) { 
                el["ev" + type] = ev; //将自定义事件存储在该元素属性下,触发时使用
            }  
        } else if (window.attachEvent) {
            el.attachEvent("on" + type, fn);    
            if (isNaN(el["cu" + type])) {
                // 自定义属性,用来间接触发触发自定义事件
                el["cu" + type] = 0; 
            }   
            var fnEv = function(event) {
                if (event.propertyName == "cu" + type) { fn.call(el); }
            };
            el.attachEvent("onpropertychange", fnEv);     
            if (!el["ev" + type]) {
                el["ev" + type] = [fnEv];
            } else {
                el["ev" + type].push(fnEv);    //同一事件的多个处理函数
            }
        }
        return this;
    },
    fireEvent: function(type) {
        var el = this.el;
        if (typeof type === "string") {
            if (document.dispatchEvent) {
                if (el["ev" + type]) {
                    el.dispatchEvent(el["ev" + type]);
                }
            } else if (document.attachEvent) {
                el["cu" + type]++;
            }    
        }    
        return this;
    },
    removeEvent: function(type, fn, capture) {
        var el = this.el;
        if (window.removeEventListener) {
            el.removeEventListener(type, fn, capture || false);
        } else if (document.attachEvent) {
            el.detachEvent("on" + type, fn);
            var arrEv = el["ev" + type];
            if (arrEv instanceof Array) {
                for (var i=0; i

测试

var fnClick = function(e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    if (target.nodeType === 1) {
        alert("点击类型:" +  e.type);
        $(target).fireEvent("sayHello");  //触发自定义事件
    }
}, sayHello1 = function() {
    alert("Hello 1");    
}, sayHello2 = function() {
    alert("Hello 2");    
};

//  梅西图片
var elImage = document.getElementById("myImg");
$(elImage)
    .addEvent("click", fnClick)
    .addEvent("sayHello", sayHello1)
    .addEvent("sayHello", sayHello2);

// 删除自定义事件按钮
var elButton = document.getElementById("myBut");
$(elButton).addEvent("click", function() {
    $(elImage)
        .removeEvent("sayHello", sayHello1)
        .removeEvent("sayHello", sayHello2);    

       alert("清除成功!");
});

html:
     
![](./meixi.jpg)

运行结果如下:
当我们点击图片,会出现下面三个弹窗


JavaScript 自定义事件(二)——Dom事件_第2张图片
alert1.png

JavaScript 自定义事件(二)——Dom事件_第3张图片
alert2.png

JavaScript 自定义事件(二)——Dom事件_第4张图片
alert3.png

当我们点击按钮:


JavaScript 自定义事件(二)——Dom事件_第5张图片
del.png

你可能感兴趣的:(JavaScript 自定义事件(二)——Dom事件)