四、伪DOM自定义事件

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

//zxx: 下面即将展示的代码目的在于学习与认识,要想实际应用可能还需要在细节上做些调整。例如,下面测试的包装器仅仅只是包裹DOM元素,并非选择器之类;$符号未增加冲突处理,且几个重要方法都暴露在全局环境中,没有闭包保护等。

原型以及new函数构造不是本文重点,因此,下面这个仅展示:

var $ = function(el) {
return new _$(el);
};
var _$ = function(el) {
this.el = el;
};
_$.prototype = {
constructor: this,
addEvent: function() {
// ...
},
fireEvent: function() {
// ...
},
removeEvent: function() {
// ...
}
}

于是我们就可以使用类似$(dom).addEvent()的语法为元素添加事件了(包括不包含浏览器行为的自定义事件)。

自定义事件的添加
如果只考虑事件添加,我们的工作其实很简单,根据支持情况,addEventListenerattachEvent方法分别添加事件(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;
}

显然,事情不会这么简单,有句古话叫做“上山容易下山难”,自定义事件添加容易,但是如何触发它们呢?——考虑到自定义事件与浏览器行为无关,同时浏览器没有直接的触发事件的方法。

自定义事件的触发
又是不可避免的,由于浏览器兼容性问题,我们要分开说了,针对标准浏览器和IE6/7等考古浏览器。

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

document.createEvent()
event.initEvent()
element.dispatchEvent()

举个板栗:

$(dom).addEvent("alert", function() {
alert("弹弹弹,弹走鱼尾纹~~");
}); // 创建
var evt = document.createEvent("HTMLEvents");
// 初始化
evt.initEvent("alert", false, false); // 触发, 即弹出文字
dom.dispatchEvent(evt);

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

参数 事件接口 初始化方法
HTMLEvents HTMLEvent initEvent()
MouseEvents MouseEvent initMouseEvent()
UIEvents UIEvent initUIEvent()

关于createEvent()方法我自己了解也不是很深入,不想滥竽充数,误人子弟,所以您有疑问我可能作答不了,希望对熟知该方法的人可以做进一步的解释说明(例如事件接口与document关系,UIEvent是什么东西等)。

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

dispatchEvent()就是触发执行了,dom.dispatchEvent(eventObject), 参数eventObject表示事件对象,是createEvent()方法返回的创建的Event对象。

2. 对于IE浏览器,由于向下很多版本的浏览器都不支持document.createEvent()方法,因此我们需要另辟蹊径(据说IE有document.createEventObject()event.fireEvent()方法,但是不支持自定义事件~~)。

IE浏览器有不少自给自足的东西,例如下面要说的这个"propertychange"事件,顾名思意,就是属性改变即触发的事件。例如文本框value值改变,或是元素id改变,或是绑定的事件改变等等。

我们可以利用这个IE私有的东西实现自定义事件的触发,大家可以先花几分钟想想……

// zxx: 假设几分钟已经过去了……

大家现在有思路了没?其实说穿了很简单,当我们添加自定义事件的时候,顺便给元素添加一个自定义属性即可。例如,我们添加自定义名为"alert"的自定义事件,顺便我们可以对元素做点小手脚:

dom.evtAlert = "2012-04-01";

再顺便把自定义事件fn塞到"propertychange"事件中:

dom.attachEvent("onpropertychange", function(e) {
if (e.propertyName == "evtAlert") {
fn.call(this);
}
});

这个,当我们需要触发自定义事件的时候,只要修改DOM上自定义的evtAlert属性的值即可:

dom.evtAlert = Math.random();	// 值变成随机数

此时就会触发dom上绑定的onpropertychange事件,又因为修改的属性名正好是"evtAlert", 于是自定义的fn就会被执行。这就是IE浏览器下事件触发实现的完整机制,应该说讲得还是蛮细的。

自定义事件的删除
与触发事件不同,事件删除,各个浏览器都提供了对于的时间删除方法,如removeEventListenerdetachEvent。不过呢,对于IE浏览器,还要多删除一个事件,就是为了实现触发功能额外增加的onpropertychange事件:

dom.detachEvent("onpropertychange", evt);
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); // 在元素上存储绑定的propertychange事件,方便删除
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<arrEv.length; i+=1) {
// 删除该方法名下所有绑定的propertychange事件
el.detachEvent("onpropertychange", arrEv[i]);
}
}
}
return this;
}
};

转: JS自定义事件的定义和触发(createEvent, dispatchEvent)的更多相关文章

  1. js自定义事件、DOM/伪DOM自定义事件

    一.说明.引言 我JS还是比较薄弱的,本文的内容属于边学边想边折腾的碎碎念,可能没什么条理,可能有表述不准确的地方,可能内容比较拗口生僻.如果您时间紧迫,或者JS造诣已深,至此您就可以点击右侧广告(木 ...

  2. 漫谈js自定义事件、DOM/伪DOM自定义事件

    一.说明.引言 我JS还是比较薄弱的,本文的内容属于边学边想边折腾的碎碎念,可能没什么条理,可能有表述不准确的地方,可能内容比较拗口生僻.如果您时间紧迫,或者JS造诣已深,至此您就可以点击右侧广告(木 ...

  3. js 自定义事件 包含 添加、激活、销毁

    1.思路 (1)构思 var eventTarget = { addEvent: function(){ //添加事件 }, fireEvent: function(){ //触发事件 }, remo ...

  4. js自定义事件

    自定义事件的本质,创建一个对象,然后把事件的名字作为对象的一个属性,然后value是一个[],把此事件的所以回调都push进去. 写一个很基本的,没有把对象暴露出去的js的自定义事件. var eve ...

  5. JS自定义事件(Dom3级事件下)

    原文出处:  http://www.w3cfuns.com/notes/11861/e21736a0b15bceca0dc7f76d77c2fb5a.html . 我拿出作者中的一段,感谢作者原创. ...

  6. cocos2d JS 自定义事件分发器(接收与传递数据) eventManager

    简而言之,它不是由系统自动触发,而是人为的干涉 较多情况用于传递数据 var _listener1 = cc.EventListener.create({ event: cc.EventListene ...

  7. js自定义事件CustomEvent、Event、TargetEvent

    1.Event Event 对象代表事件的状态,比如事件在其中发生的元素.键盘按键的状态.鼠标的位置.鼠标按钮的状态. 事件通常与函数结合使用,函数不会在事件发生前被执行! Event的事件都是系统自 ...

  8. JS自定义事件之选项卡

    自定义事件是一种处理与DOM产生交互的代码逻辑片段之间耦合的很好的架构方法. 一个简单的jQuery插件——选项卡 让ul列表来响应点击事件.当用户点击一个列表项时,给这个列表项添加一个名为activ ...

  9. vue.js 自定义事件

    <div id="app"> <h2>{{num}}</h2> <h1>全局组件</h1> <my-compone ...

随机推荐

  1. Asp.Net MVC 常用开发方式之EF Code First

    在我们的工作和学习当中,经常会遇到中小型项目,这些项目除了业务上的区别较大外,对于底层和数据访问,其实都差不多.记得以前做项目时,每次都要重复的写底层操作数据库的代码,不仅浪费时间,也无太大意思,后来 ...

  2. Euclid gcd规则的证明

    Euclid 规则:如果x和y都是正整数,而且x>=y,那么gcd(x,y)=gcd(x mod y, y) 假设x和y的gcd为a,那么必然有 x=a*n1 y=a*n2(gcd(n1,n2) ...

  3. 我定制的jquery ui主题

    打开网址 http://jqueryui.com/themeroller/,找到Gallery找到Redmond点击edit 将圆角设置成3px,让圆角更低调:将下面的每个Background的背景图 ...

  4. C#学习日志 day 6 ------ 常用正则表达式例举

    c#支持正则表达式匹配文本,这里讨论一下正则表达式的使用方法以及例举一些常用的正则表达式的匹配. 1.在vs中使用正则表达式 在vs中使用正则表达式,需要using System.Text.Regul ...

  5. python filter内建函数

    以下是filter函数的官方文档,注意最后一段,当function不为None时,函数相似于[item for item in iterable if function(item)],function ...

  6. [原创]obj-c编程17:键值观察(KVO)

    原文链接:[原创]obj-c编程17:键值观察(KVO) 系列专栏链接:objective-c 编程系列 说完了前面一篇KVC,不能不说说它的应用KVO(Key-Value Observing)喽.K ...

  7. TCPL 行计数

    C programming language: P13 行计数 e.g. #include <stdio.h>int main(void){    int c, nb, nt, nl;   ...

  8. SQL Server 缓存清理的一些原因

    1.dbcc freeproccache; 2.dbcc freesystemcache('all') | dbcc freesystemcache('pool_name'); 3.declare @ ...

  9. 在 Windows Azure 虚拟机中如何备份和还原 Windows 系统磁盘

    备份和还原对于操作真实的系统来说至关重要.对于 Windows Azure 虚拟机环境中的 Windows Server,可以根据自身的需求选择多种不同的工具或将这些工具结合使用来实现备份.下面将对这 ...

  10. Ubuntu输入password登陆后又跳回到登录界面

    现象:在Ubuntu登陆界面输入password之后.黑屏一闪而且出现了check battery state之类的文字之后,又跳转到登录界面. 原因:主文件夹下的.Xauthority文件拥有者变成 ...