据说每个大牛、小牛都应该有自己的库——Event处理
今天抽时间写了一部分Event处理方面的函数愈发的觉得jQuery的优秀,自己前期的想法太粗糙,造成后面这些函数参数很多,操作很很不直观,看样子是要重构的节奏,还好小伙儿伴们安慰,架构都是改出来的。继续探索吧
浏览器兼容性
写Event处理的库函数一个难点就在于浏览器兼容性问题,在IE低版本浏览器中事件对象始终在window.event属性中,而在其它浏览器中event会作为事件处理程序中作为第一个参数传入。而且其Event对象的属性和方法也有诸多差异,在JavaScript与HTML交互——事件中基本有所总结,不过还是抄一段关于事件处理程序绑定方面的差异
1. 参数个数不相同,这个最直观,addEventListener有三个参数,attachEvent只有两个,attachEvent添加的事件处理程序只能发生在冒泡阶段,addEventListener第三个参数可以决定添加的事件处理程序是在捕获阶段还是冒泡阶段处理(我们一般为了浏览器兼容性都设置为冒泡阶段)
2. 第一个参数意义不同,addEventListener第一个参数是事件类型(比如click,load),而attachEvent第一个参数指明的是事件处理函数名称(onclick,onload)
3. 事件处理程序的作用域不相同,addEventListener得作用域是元素本身,this是指的触发元素,而attachEvent事件处理程序会在全局变量内运行,this是window
4. 为一个事件添加多个事件处理程序时,执行顺序不同,addEventListener添加会按照添加顺序执行,而attachEvent添加多个事件处理程序时顺序无规律(添加的方法少的时候大多是按添加顺序的反顺序执行的,但是添加的多了就无规律了),所以添加多个的时候,不依赖执行顺序的还好,若是依赖于函数执行顺序,最好自己处理,不要指望浏览器
最简单的四个
先写四个最简单的
- getEvent:获取事件对象
- getTarget:获取事件源对象
- preventDefault:阻止事件默认行为
- stopPropagation:阻止事件冒泡
(function (window) {
var ssLib = {
getEvent: function (e) {
return e ? e : window.event;
},
getTarget: function (e) {
var e = this.getEvent(e);
return e.target || e.srcElement;
},
preventDefault: function (e) {
var e = this.getEvent(e);
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false;
}
},
stopPropagation: function (e) {
var e = this.getEvent(e);
if (e.stopPropagation) {
e.stopPropagation();
} else {
e.cancelBubble = true;
}
}
};
window.ssLib = window.ss = ssLib;
})(window);
代码很简单,相信聪明的小伙儿伴们一看就懂,就不多做解释了
addEvent/removeEvent
- addEvent:为元素绑定事件处理程序
- removeEvent:移除元素事件处理程序
addEvent: function (element, type, handler, key) {
var key = key || handler;
if (element[type + key])
return false;
if (typeof element.addEventListener != "undefined") {
element[type + key] = handler;
element.addEventListener(type, handler, false);
}
else {
element['e' + type + key] = handler;
element[type + key] = function () {
element['e' + type + key](window.event);
};
element.attachEvent('on' + type, element[type + key]);
}
return true;
},
removeEvent: function (element, type, key) {
if (!element[type + key])
return false;
if (typeof element.removeEventListener != "undefined") {
element.removeEventListener(type, element[type + key], false);
}
else {
element.detachEvent("on" + type, element[type + key]);
element['e' + type + key] = null;
}
element[type + key] = null;
return true;
},
这两个函数兼容性写法有很多,结合了很多大牛的写法后我用的上面版本,这么些看似很复杂,实际上主要解决了上面提到的、除了多个事件处理程序执行顺序问题的浏览器兼容性问题,比较难看懂的IE绑定部分就是为了处理this而写的。
在使用的时候,可以显示传入一个key用于内部识别绑定函数,如果不绑定则使用handler本身作为key,所以可以这么用
ssLib.addEvent(element,'click',function(){},'test');
ssLib.removeEvent(element,'click','test');
function handler(){}
ssLib.addEvent(element,'click',handler);
ssLib.removeEvent(element,'click',handler);
on/off
这个是看到jQuery的on/delegate和YUI 的delegate后萌发的想法,不过平时老用人家的没自己写过,仓促写了一个,感慨颇多,还是jQuery好使
on: function (parent, type, handler,validater,key) {
var _key=key || handler;
parent['on'+type+_key]=function (e) {
var target = ssLib.getTarget(e);
var isFire = validater(target);
if (isFire) {
target[type + _key] = handler;
target[type + _key](e);
}
};
ssLib.addEvent(parent, type,parent['on'+type+_key] , key);
},
off: function (parent, type, key) {
if(typeof key=='function'){
ssLib.removeEvent(parent, type, parent['on'+type+key]);
}else{
ssLib.removeEvent(parent, type, key);
}
parent['on'+type+key]=null;
}
写法和刚才类似,不停的绕来绕去也是解决this问题,可以这么用
<div id="test">
<div id="t1">T1</div>
<div id="t2">T2</div>
</div>
var parent = document.getElementById('test');
var handler=function () {
alert(this.id);
}
var validater=function (obj) {
if(obj.parentNode.id=='test'){
return true;
}else{
return false;
}
}
ss.on(parent, 'click', handler, validater);
ss.off(parent,'click',handler);
ss.on(parent, 'click', handler, validater,'delegate');
ss.off(parent,'click','delegate');
ready
用过jQuery的同学肯定知道这个函数,写自己库的时候是各种惊羡啊,于是乎加到了自己的库里
ready: function (fn) {
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", function () {
document.removeEventListener("DOMContentLoaded", arguments.callee, false);// 防止多次调用
fn();
}, false);
} else if (document.addEvent) {
var doc = window.document, done = false;
// only fire once
var init = function () {
if (!done) {
done = true;
fn();
}
};
// polling for no errors
(function () {
try {
// throws errors until after ondocumentready
doc.documentElement.doScroll('left');// 文档加载完成后此方法可用
} catch (e) {
setTimeout(arguments.callee, 50);
return;
}
// no errors, fire
init();
})();
// trying to always fire before onload
doc.onreadystatechange = function () {
if (doc.readyState == 'complete') {
doc.onreadystatechange = null;
init();
}
};
}
}
要想看懂上面代码最好看看An alternative for DOMContentLoaded on Internet Explorer
在现代浏览器中文档加载完后会触发“DOMContentLoaded”事件,而在底版本IE中文档加载完成后会doScroll方法会生效
Event部分源代码
(function (window) {
var ssLib = {
getEvent: function (e) {
return e ? e : window.event;
},
getTarget: function (e) {
var e = this.getEvent(e);
return e.target || e.srcElement;
},
preventDefault: function (e) {
var e = this.getEvent(e);
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false;
}
},
stopPropagation: function (e) {
var e = this.getEvent(e);
if (e.stopPropagation) {
e.stopPropagation();
} else {
e.cancelBubble = true;
}
},
addEvent: function (element, type, handler, key) {
var key = key || handler;
if (element[type + key])
return false;
if (typeof element.addEventListener != "undefined") {
element[type + key] = handler;
element.addEventListener(type, handler, false);
}
else {
element['e' + type + key] = handler;
element[type + key] = function () {
element['e' + type + key](window.event);
};
element.attachEvent('on' + type, element[type + key]);
}
return true;
},
removeEvent: function (element, type, key) {
if (!element[type + key])
return false;
if (typeof element.removeEventListener != "undefined") {
element.removeEventListener(type, element[type + key], false);
}
else {
element.detachEvent("on" + type, element[type + key]);
element['e' + type + key] = null;
}
element[type + key] = null;
return true;
},
ready: function (fn) {
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", function () {
document.removeEventListener("DOMContentLoaded", arguments.callee, false);
fn();
}, false);
} else if (document.attachEvent) {
var doc = window.document, done = false;
// only fire once
var init = function () {
if (!done) {
done = true;
fn();
}
};
// polling for no errors
(function () {
try {
// throws errors until after ondocumentready
doc.documentElement.doScroll('left');
} catch (e) {
setTimeout(arguments.callee, 50);
return;
}
// no errors, fire
init();
})();
// trying to always fire before onload
doc.onreadystatechange = function () {
if (doc.readyState == 'complete') {
doc.onreadystatechange = null;
init();
}
};
}
},
on: function (parent, type, handler, validater, key) {
var _key = key || handler;
parent['on' + type + _key] = function (e) {
var target = ssLib.getTarget(e);
var isFire = validater(target);
if (isFire) {
target[type + _key] = handler;
target[type + _key](e);
}
};
ssLib.addEvent(parent, type, parent['on' + type + _key], key);
},
off: function (parent, type, key) {
if (typeof key == 'function') {
ssLib.removeEvent(parent, type, parent['on' + type + key]);
} else {
ssLib.removeEvent(parent, type, key);
}
parent['on' + type + key] = null;
}
};
window.ssLib = window.ss = ssLib;
})(window);
据说每个大牛、小牛都应该有自己的库——Event处理的更多相关文章
- 据说每个大牛、小牛都应该有自己的库——DOM处理续
在上篇据说每个大牛.小牛都应该有自己的库——DOM处理最后剩下attr()和css()方法没有处理,因为这两个方法当时并不自计划中,是写着写着突然想到的,一时间没有特别好的思路,当时已十一点多了,就去 ...
- 据说每个大牛、小牛都应该有自己的库——DOM处理
这几天整理了一下思路,本来觉得DOM部分会有很多东西,但是忽然发现频繁使用的其实并不太多 class class处理部分主要有四个 hasClass:检查元素是否包含某个class addClass: ...
- 据说每个大牛、小牛都应该有自己的库——JavaScript原生对象拓展
在据说每个大牛.小牛都应该有自己的库——框架篇中我扬言要做个小牛,没想到一天没更新,小伙儿伴们就戏谑的问我,油哥是不是要太监了?其实事情是这个样子的,这不是太监的节奏,一是,关于写个自己的库的想法由来 ...
- 据说每个大牛、小牛都应该有自己的库——Ajax
蹉跎到今天终于要写Ajax部分了,平时工作中除了选择器我用jQuery的最多的就是ajax,所以这部分在自己的框架中必不可少. XMLHttpRequest 我以为对每个使用过Ajax的人来说XMLH ...
- 让所有网站都提供API的Python库:Toapi
这是一个让所有网站都提供API的Python库.以前,我们爬取数据,然后把数据存起来,再创造一个api服务以便其他人可以访问.为此,我们还要定期更新我们的数据.这个库让这一切变得容易起来.你要做的就是 ...
- Xcode 5.1 编译模拟器以及真机都能使用的静态库
Xcode 5.1.dmg 下载地址 http://pan.baidu.com/s/1jGJpKm6 1.新建 Framework & Library 工程 我起名叫ShowInfo,下面为其 ...
- pycharm每次新建项目都要重新安装一些第三方库的解决办法(转载防删)
目前有三个解决办法,也是亲测有用的: 第一个方法:因为之前有通过pycharm的project interpreter里的+号添加过一些库,但添加的库只是指定的项目用的,如果想要用,就必须用之前的项目 ...
- 每个android项目都应该使用的android 库
http://blog.teamtreehouse.com/android-libraries-use-every-project A good developer knows to never re ...
- JavaScript原生对象拓展
JavaScript原生对象拓展 在据说每个大牛.小牛都应该有自己的库——框架篇中我扬言要做个小牛,没想到一天没更新,小伙儿伴们就戏谑的问我,油哥是不是要太监了?其实事情是这个样子的,这不是太监的节奏 ...
随机推荐
- js跨域访问
什么是跨域 JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象.但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦.这里把涉及到跨域的一些问题简单地整理一下: 首 ...
- javascript父级鼠标移入移出事件中的子集影响父级的处理方法
一.我们先分析其产生的原因: 1.当鼠标从父级移入子集时触发了父级的两个事件:a.父级的mouseout事件(父级离开到子集):b.由于事件冒泡影响,又触发了父级的mouseover事件(父级移入父级 ...
- linux下的device tree
在我个人的理解,device tree就是描述硬件设备的,目前有什么配置,把这些配置信息告诉linux内核,让内核去识别,增强了内核的通用性,不用因为平台不同而每次都要编译新内核了. 配置device ...
- 00024500-0000-0000-C000-000000000046错误,在sys.web配置节添加一个用户给web站点。
<identity impersonate ="true" userName="administrator" password="123456& ...
- ORA-12543: TNS:destination host unreachable
在连接Oracle数据库时,如果使用Tnsnames.ora中配置的数据源名称有时会报 ORA-12543: TNS:destination host unreachable 异常,比如:在Tnsna ...
- C# 换行符
winform 中 TextBox 的 Multiline属性设置为 true ,敲入几个字符和几个回车,然后保存到数据库,再从数据库中读取出来赋值给TextBox,换行符丢失.将读取出的字符串中的& ...
- 最小生成树算法——prim算法
prim算法:从某一点开始,去遍历相邻的边,然后将权值最短的边加入集合,同时将新加入边集中的新点遍历相邻的边更新边值集合(边值集合用来找出新的最小权值边),注意每次更新都需将cost数组中的点对应的权 ...
- .net配置文件读取
public static string LogPath { get { return AppSettingValue(); } } public static string AppSettingVa ...
- 移动App崩溃的测试用例设计
我们的日常生活中对移动设备越来越多的使用意味着移动App测试这个主题已成为需要考虑的一个无法避免的问题.根据最近的调查研究,用户难以容忍有bug的移动App. 移动App Bug的影响是用户体验差.A ...
- 【动态规划】bzoj1663 [Usaco2006 Open]赶集
http://blog.csdn.net/u011265346/article/details/44906469 #include<cstdio> #include<algorith ...