js可以自定义事件么 比如我想给dom元素加个ondrag事件? 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 你说的事件是指什么?是让所有的DOM都有这个方法,就像focus, blur什么的一样,还是给所有元素绑定一个Event事件 可以,自己写~ 但这个 ondrag应该是满 足某个条件触发的事件比如:<div id="test" style="background:blue; width:200px; height:50px" >test</div><script>onload = function(){ var test = document.getElementById('test'); test.ondrag = function(){ alert(this.name) } test.onclick = function(){ if(!this.name){ this.name='test'; }else{ this.ondrag(); } }}</script> 这是自定义事件么?document.addEventListener("ondrag", function() {}, false);这才是自定义事件吧 addEventListener只能是浏览器默认的事件。 我晕,感情你都没搞清楚什么是事件。你是不是想像这样的$(id).ondrag(); 可以模拟事件,例如下面的例子(来自http://topic.csdn.net/t/20060425/09/4711080.html) <SCRIPT LANGUAGE="JavaScript"> <!-- function EventTarget(){ this._listeners={}; this.addEventListener=function(sType,fnHandle){ if ('function'!=typeof fnHandle){return;} var ls=this._listeners[sType]; if(!ls)ls=this._listeners[sType]={}; ls[EventTarget.toHashCode(fnHandle)]=fnHandle; }; this.dispatchEvent=function(sType){ if(!this._listeners[sType])return; for(var hc in this._listeners[sType]){ this._listeners[sType][hc].call(this); } }; } EventTarget.toHashCode=function(o){if(o._hashCode)return o._hashCode;return o._hashCode="_"+(EventTarget._hashCodeCounter++).toString(32);}; EventTarget._hashCodeCounter=0; function TestEvent(){ EventTarget.call(this); this.test=function(){ alert('test方法开始执行'); this.dispatchEvent('onTest'); alert('test方法执行完毕'); }; }; var test=new TestEvent(); test.addEventListener('onTest',function(){alert('监听到test事件');}); test.test(); var test2=new TestEvent(); test2.test(); //--> </SCRIPT> attachEvent addEventListener baidu上有这篇帖子 开始没点进去看。Dean Edwards 最近有篇文章很精彩,忍不住在这里翻译下。-- Split --很多 Javascript 框架都提供了自定义事件(custom events),例如 jQuery、YUI 以及 Dojo 都支持“document ready”事件。而部分自定义事件是源自回调(callback)。回调将多个事件句柄存储在数组中,当满足触发条件时,回调系统则会从数组中获取对应的句柄并执行。那么,这会有什么陷阱呢?在回答这个问题之前,我们先看下代码。下面是两段代码依次绑定到 DOMContentLoaded 事件中document.addEventListener("DOMContentLoaded", function() { console.log("Init: 1"); DOES_NOT_EXIST++; // 这里会抛出异常}, false);document.addEventListener("DOMContentLoaded", function() { console.log("Init: 2");}, false);那么运行这段代码会返回什么信息?显然,会看见这些(或者类似的):Init: 1Error: DOES_NOT_EXIST is not definedInit: 2可以看出,两段函数都被执行。即使第一个函数抛出了个异常,但并不影响第二段代码运行。麻烦OK,我们回来看下常见框架中的回调系统。首先,我们看下 jQuery 的(因为它很流行):$(document).ready(function() { console.log("Init: 1"); DOES_NOT_EXIST++; // 这里会抛出异常});$(document).ready(function() { console.log("Init: 2");});然后控制台中输出了什么?Init: 1Error: DOES_NOT_EXIST is not defined这样问题就很明了了。回调系统其实很脆弱 -- 如果中间有段代码抛出了异常,那么其余将不会被执行。想象下在实际情况中,这后果可能会更严重,譬如有些糟糕的插件可能会“一粒老屎坏了一锅粥”。其他的框架,Dojo 的情况和 jQuery 类似,不过 YUI 的情况有些许不同。在它的回调系统中,使用了 try/catch 语句避免因异常发生的中断。但有个小小的负面影响,就是看不到相应的异常了。YAHOO.util.Event.onDOMReady(function() { console.log("Init: 1"); DOES_NOT_EXIST++; // 这里会抛出异常});YAHOO.util.Event.onDOMReady(function() { console.log("Init: 2");});输出:Init: 1Init: 2那么,有无完美的解决方案呢?解决方案我想到了个解决方案,就是将回调和事件结合起来。可以先建立个事件,当回调触发时才运行它。由于每个事件都有其独立的运行环境(execution context),那么即使其中某个事件抛出了异常将不会影响其他的回调。这听起来有点复杂,还是代码说话吧。var currentHandler;// 标准事件支持if (document.addEventListener) { document.addEventListener("fakeEvents", function() { // 执行回调 currentHandler(); }, false); // 新建事件 var dispatchFakeEvent = function() { var fakeEvent = document.createEvent("UIEvents"); fakeEvent.initEvent("fakeEvents", false, false); document.dispatchEvent(fakeEvent); };} else { // 针对 IE 的代码在后面详细阐述}var onLoadHandlers = [];// 将回调加入数组中function addOnLoad(handler) { onLoadHandlers.push(handler);};// 逐条取出回调,并利用上述新建的事件执行onload = function() { for (var i = 0; i < onLoadHandlers.length; i++) { currentHandler = onLoadHandlers[i]; dispatchFakeEvent(); }};万事俱备,让我们将上面坨代码扔到我们新的回调系统中addOnLoad(function() { console.log("Init: 1"); DOES_NOT_EXIST++; // 这里会抛出异常});addOnLoad(function() { console.log("Init: 2");});上帝保佑,看运行结果我们看到了如下的信息:Init: 1Error: DOES_NOT_EXIST is not definedInit: 2赞!这就是我们期望的。这两个回调都运行而且互不影响,并且还能获得异常的信息,太好了!好了,我们回过头来扶起 Internet Explorer 这个“阿斗”(我已经听见场下观众的建议了)。Internet Explorer 不支持 W3C 的标准事件规范,谢天谢地好在它有自身的实现 -- 有个 fireEvents 的方法,但只能在用户事件的时候触发(例如用户点击 click)。不过终于找到了门道,我们来看下具体代码:var currentHandler;if (document.addEventListener) { // 省略上述的代码} else if (document.attachEvent) { // MSIE // 利用扩展属性,当此对象被改变时触发 document.documentElement.fakeEvents = 0; document.documentElement.attachEvent("onpropertychange", function(event) { if (event.propertyName == "fakeEvents") { // 执行回调 currentHandler(); } }); dispatchFakeEvent = function(handler) { // 触发 propertychange 事件 document.documentElement.fakeEvents++; };}简而言之,殊途同归,只是针对 Internet Explorer 使用了 propertychange 事件作为触发器。更新有些用户留言建议使用 setTimeout:try { callback(); } catch(e){ setTimeout(function(){ throw e; }, 0); }而下面是我的考虑如没特别的要求,其实定时器的确也能搞定这问题。上面仅仅是举例说明了这一技术的可行性。意义在于,目前很多框架在回调系统的实现都非常的脆弱,这或许能给这些框架能它们提供更优化的思路。而定时器的实现并非实际的触发了事件,在实际事件中,事件会被顺序的执行、可相互影响(譬如冒泡)、还可以停止 -- 而这些是定时器无法做到的。总之,最重要的是已经实现了包括 Internet Explorer 在内,使用事件执行回调的实现。如果你正编写基于事件代理的回调系统,我想你会对这一技术感兴趣的。更新2Prototype 在针对 Internet Explorer 的自定义事件处理上,也是同上述的方法触发回调:http://andrewdupont.net/2009/03/24/link-dean-edwards/译注,Prototype 1.6 对应的代码,摘记如下:function createWrapper(element, eventName, handler) { var id = getEventID(element); // 获取绑定事件的 ID var c = getWrappersForEventName(id, eventName); // 获取对应的事件的所有回调 if (c.pluck("handler").include(handler)) return false; // 避免重复绑定 // 新建回调 var wrapper = function(event) { if (!Event || !Event.extend || (event.eventName && event.eventName != eventName)) return false; Event.extend(event); handler.call(element, event); }; // 加入到回调数组 wrapper.handler = handler; c.push(wrapper); return wrapper;}function observe(element, eventName, handler) { element = $(element); // 对应事件的元素 var name = getDOMEventName(eventName); // 事件执行方式 var wrapper = createWrapper(element, eventName, handler); // 封装回调 if (!wrapper) return element; // 绑定事件 if (element.addEventListener) { element.addEventListener(name, wrapper, false); } else { element.attachEvent("on" + name, wrapper); } return element;}// 调用方式document.observe("dom:loaded", function() { console.log("Init: 1"); DOES_NOT_EXIST++;});document.observe("dom:loaded", function() { console.log("Init: 2");});看把 Prototype 的作者给乐的 :-/-- Split --在本人看来,原文的作者表述的技术点,除了如何创建健壮的回调系统外,其实还有两条。其一,就是如何保证在出现异常的时,继续运行期望的代码;其二,就是如何创建互不干扰的“运行环境”。原文提到的 createEvent 和 setTimeout 都是好办法,只是处理原作者所言在回调系统中,的确使用 createEvent 会比较合适。setTimeout 相对应的详细信息,可移步到 Realazy 兄的相关文章。而即使出错也能继续运行期望的代码,其实可以考虑使用 finally 语句,下面是个例子:var callbacks = [ function() { console.log(0); }, function() { console.log(1); throw new Error; }, function() { console.log(2); }, function() { console.log(3); }];for(var i = 0, len = callbacks.length; i < len; i++) { try { callbacks[i](); } catch(e) { console.info(e); // 获得异常信息 } finally { continue; }}这一灵感同样来自 Dean Edwards 文章后的回复,在这里也贴下吧:function iterate(callbacks, length, i) { if (i >= length) return; try { callbacks[i](); } catch(e) { throw e; } finally { iterate(callbacks, length, i+1); }} 一个简单的局部变量的作用域问题 php数据库排序问题 关于<input onClick>的问题 js如何在指定id 生成html代码呢? 请问淘宝商城左边的商品分类功能如何实现。谢谢 哪有js写的类似于portlet界面的代码?请大家介绍一下。 再次请教高手 如何补数字位 小弟初学javascript,有句程序读不懂,请各位大哥指点! 请教大虾(急急急急急!!!) Asp.NET引入多个js文件,为什么只有第一个起作用? 在线 求IE6、IE7、IE8通用的JS存取COOKIE方法
但这个 ondrag应该是满 足某个条件触发的事件比如:
<div id="test" style="background:blue; width:200px; height:50px" >test</div>
<script>
onload = function(){
var test = document.getElementById('test');
test.ondrag = function(){ alert(this.name) } test.onclick = function(){
if(!this.name){
this.name='test';
}else{
this.ondrag();
}
}
}
</script>
document.addEventListener("ondrag", function() {}, false);
这才是自定义事件吧
<!--
function EventTarget(){
this._listeners={};
this.addEventListener=function(sType,fnHandle){
if ('function'!=typeof fnHandle){return;}
var ls=this._listeners[sType];
if(!ls)ls=this._listeners[sType]={};
ls[EventTarget.toHashCode(fnHandle)]=fnHandle;
};
this.dispatchEvent=function(sType){
if(!this._listeners[sType])return;
for(var hc in this._listeners[sType]){
this._listeners[sType][hc].call(this);
}
};
}
EventTarget.toHashCode=function(o){if(o._hashCode)return o._hashCode;return o._hashCode="_"+(EventTarget._hashCodeCounter++).toString(32);};
EventTarget._hashCodeCounter=0;
function TestEvent(){
EventTarget.call(this);
this.test=function(){
alert('test方法开始执行');
this.dispatchEvent('onTest');
alert('test方法执行完毕');
};
};
var test=new TestEvent();
test.addEventListener('onTest',function(){alert('监听到test事件');});
test.test();
var test2=new TestEvent();
test2.test();
//-->
</SCRIPT>
Dean Edwards 最近有篇文章很精彩,忍不住在这里翻译下。-- Split --很多 Javascript 框架都提供了自定义事件(custom events),例如 jQuery、YUI 以及 Dojo 都支持“document ready”事件。而部分自定义事件是源自回调(callback)。回调将多个事件句柄存储在数组中,当满足触发条件时,回调系统则会从数组中获取对应的句柄并执行。那么,这会有什么陷阱呢?在回答这个问题之前,我们先看下代码。下面是两段代码依次绑定到 DOMContentLoaded 事件中document.addEventListener("DOMContentLoaded", function() {
console.log("Init: 1");
DOES_NOT_EXIST++; // 这里会抛出异常
}, false);document.addEventListener("DOMContentLoaded", function() {
console.log("Init: 2");
}, false);
那么运行这段代码会返回什么信息?显然,会看见这些(或者类似的):Init: 1
Error: DOES_NOT_EXIST is not defined
Init: 2
可以看出,两段函数都被执行。即使第一个函数抛出了个异常,但并不影响第二段代码运行。麻烦
OK,我们回来看下常见框架中的回调系统。首先,我们看下 jQuery 的(因为它很流行):$(document).ready(function() {
console.log("Init: 1");
DOES_NOT_EXIST++; // 这里会抛出异常
});$(document).ready(function() {
console.log("Init: 2");
});
然后控制台中输出了什么?Init: 1
Error: DOES_NOT_EXIST is not defined
这样问题就很明了了。回调系统其实很脆弱 -- 如果中间有段代码抛出了异常,那么其余将不会被执行。想象下在实际情况中,这后果可能会更严重,譬如有些糟糕的插件可能会“一粒老屎坏了一锅粥”。其他的框架,Dojo 的情况和 jQuery 类似,不过 YUI 的情况有些许不同。在它的回调系统中,使用了 try/catch 语句避免因异常发生的中断。但有个小小的负面影响,就是看不到相应的异常了。YAHOO.util.Event.onDOMReady(function() {
console.log("Init: 1");
DOES_NOT_EXIST++; // 这里会抛出异常
});YAHOO.util.Event.onDOMReady(function() {
console.log("Init: 2");
});
输出:Init: 1
Init: 2
那么,有无完美的解决方案呢?解决方案
我想到了个解决方案,就是将回调和事件结合起来。可以先建立个事件,当回调触发时才运行它。由于每个事件都有其独立的运行环境(execution context),那么即使其中某个事件抛出了异常将不会影响其他的回调。这听起来有点复杂,还是代码说话吧。var currentHandler;// 标准事件支持
if (document.addEventListener) {
document.addEventListener("fakeEvents", function() {
// 执行回调
currentHandler();
}, false); // 新建事件
var dispatchFakeEvent = function() {
var fakeEvent = document.createEvent("UIEvents");
fakeEvent.initEvent("fakeEvents", false, false);
document.dispatchEvent(fakeEvent);
};
} else {
// 针对 IE 的代码在后面详细阐述
}var onLoadHandlers = [];// 将回调加入数组中
function addOnLoad(handler) {
onLoadHandlers.push(handler);
};// 逐条取出回调,并利用上述新建的事件执行
onload = function() {
for (var i = 0; i < onLoadHandlers.length; i++) {
currentHandler = onLoadHandlers[i];
dispatchFakeEvent();
}
};
万事俱备,让我们将上面坨代码扔到我们新的回调系统中addOnLoad(function() {
console.log("Init: 1");
DOES_NOT_EXIST++; // 这里会抛出异常
});addOnLoad(function() {
console.log("Init: 2");
});
上帝保佑,看运行结果我们看到了如下的信息:Init: 1
Error: DOES_NOT_EXIST is not defined
Init: 2
赞!这就是我们期望的。这两个回调都运行而且互不影响,并且还能获得异常的信息,太好了!好了,我们回过头来扶起 Internet Explorer 这个“阿斗”(我已经听见场下观众的建议了)。Internet Explorer 不支持 W3C 的标准事件规范,谢天谢地好在它有自身的实现 -- 有个 fireEvents 的方法,但只能在用户事件的时候触发(例如用户点击 click)。不过终于找到了门道,我们来看下具体代码:var currentHandler;if (document.addEventListener) {
// 省略上述的代码
} else if (document.attachEvent) { // MSIE
// 利用扩展属性,当此对象被改变时触发
document.documentElement.fakeEvents = 0;
document.documentElement.attachEvent("onpropertychange", function(event) {
if (event.propertyName == "fakeEvents") {
// 执行回调
currentHandler();
}
}); dispatchFakeEvent = function(handler) {
// 触发 propertychange 事件
document.documentElement.fakeEvents++;
};
}
简而言之,殊途同归,只是针对 Internet Explorer 使用了 propertychange 事件作为触发器。更新
有些用户留言建议使用 setTimeout:try { callback(); } catch(e){ setTimeout(function(){ throw e; }, 0); }
而下面是我的考虑如没特别的要求,其实定时器的确也能搞定这问题。
上面仅仅是举例说明了这一技术的可行性。意义在于,目前很多框架在回调系统的实现都非常的
脆弱,这或许能给这些框架能它们提供更优化的思路。
而定时器的实现并非实际的触发了事件,在实际事件
中,事件会被顺序的执行、可相互影响(譬如冒泡)、
还可以停止 -- 而这些是定时器无法做到的。
总之,最重要的是已经实现了包括 Internet Explorer 在内,使用事件执行回调的实现。如果你正编写基于事件代理的回调系统,我想你会对这一技术感兴趣的。更新2
Prototype 在针对 Internet Explorer 的自定义事件处理上,也是同上述的方法触发回调:http://andrewdupont.net/2009/03/24/link-dean-edwards/译注,Prototype 1.6 对应的代码,摘记如下:function createWrapper(element, eventName, handler) {
var id = getEventID(element); // 获取绑定事件的 ID
var c = getWrappersForEventName(id, eventName); // 获取对应的事件的所有回调
if (c.pluck("handler").include(handler)) return false; // 避免重复绑定 // 新建回调
var wrapper = function(event) {
if (!Event || !Event.extend ||
(event.eventName && event.eventName != eventName))
return false; Event.extend(event);
handler.call(element, event);
}; // 加入到回调数组
wrapper.handler = handler;
c.push(wrapper);
return wrapper;
}function observe(element, eventName, handler) {
element = $(element); // 对应事件的元素
var name = getDOMEventName(eventName); // 事件执行方式 var wrapper = createWrapper(element, eventName, handler); // 封装回调 if (!wrapper) return element; // 绑定事件
if (element.addEventListener) {
element.addEventListener(name, wrapper, false);
} else {
element.attachEvent("on" + name, wrapper);
} return element;
}// 调用方式
document.observe("dom:loaded", function() {
console.log("Init: 1");
DOES_NOT_EXIST++;
});document.observe("dom:loaded", function() {
console.log("Init: 2");
});
看把 Prototype 的作者给乐的 :-/-- Split --在本人看来,原文的作者表述的技术点,除了如何创建健壮的回调系统外,其实还有两条。其一,就是如何保证在出现异常的时,继续运行期望的代码;其二,就是如何创建互不干扰的“运行环境”。原文提到的 createEvent 和 setTimeout 都是好办法,只是处理原作者所言在回调系统中,的确使用 createEvent 会比较合适。setTimeout 相对应的详细信息,可移步到 Realazy 兄的相关文章。而即使出错也能继续运行期望的代码,其实可以考虑使用 finally 语句,下面是个例子:var callbacks = [
function() { console.log(0); },
function() { console.log(1); throw new Error; },
function() { console.log(2); },
function() { console.log(3); }
];for(var i = 0, len = callbacks.length; i < len; i++) {
try {
callbacks[i]();
} catch(e) {
console.info(e); // 获得异常信息
} finally {
continue;
}
}
这一灵感同样来自 Dean Edwards 文章后的回复,在这里也贴下吧:function iterate(callbacks, length, i) {
if (i >= length) return; try {
callbacks[i]();
} catch(e) {
throw e;
} finally {
iterate(callbacks, length, i+1);
}
}