据说每个大牛、小牛都应该有自己的库——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原生对象拓展 在据说每个大牛.小牛都应该有自己的库——框架篇中我扬言要做个小牛,没想到一天没更新,小伙儿伴们就戏谑的问我,油哥是不是要太监了?其实事情是这个样子的,这不是太监的节奏 ...
随机推荐
- base64格式的图片如何上传到oss
---恢复内容开始--- 对于base64图片的上传这个东西,一直是一个问题尤其是上传到oss.我们这次开发由于需要修剪图片,使用了h5的很多新特性. h5修剪图片,使用了我们的canvas.这个步骤 ...
- 父窗口,子窗口之间的JS"通信"方法
今天需要在iframe内做一个弹窗,但使用弹窗组件的为子窗口,所以弹窗只在子窗口中显示掩膜层和定位,这样不符合需求. 后来晓勇哥指点,了解到一个以前一直没关注到的东西,每个窗口的全局变量,其实都存在对 ...
- MVC3在IIS7.5发布(部署)报403.14错误的解决办法
MVC3在IIS7.5发布(部署)报403.14错误的解决办法 错误现象: 报403.14 forbidden错误 web服务器被配置为不列出此目录的内容. 解决办法: 检查站点的处理程序映射 ...
- 【Java】使用iText生成PDF文件
iText介绍 iText是著名的开放源码的站点sourceforge一个项目,是用于生成PDF文档的一个java类库.通过iText不仅可以生成PDF或rtf的文档,而且可以将XML.Html文件转 ...
- <form>属性
当form表单中action没有值时,默认当前页方法.
- c#利用WebClient和WebRequest获取网页源代码的比较
前几天举例分析了用asp+xmlhttp获取网页源代码的方法,但c#中一般是可以利用WebClient类和WebRequest类获取网页源代码.下面分别说明这两种方法的实现. WebClient类获取 ...
- 1154. Easy sort
#include<iostream>#include<cmath>#include<iomanip>#include<algorithm>using n ...
- sublime text3使用小结
一.下载 http://www.sublimetext.com/2 sublime text2下载页 http://www.sublimetext.com/3 sublime text3下载页 ...
- Xamarin studio配置问题
最近对Xamarin很感兴趣,就下班抽空在家里的电脑上进行配置,于是乎出现了各种问题,对此进行总结. 1. Cannot find `aapt.exe`. Please install the And ...
- MATLAB-octave中平面向量场图的可视化
quiver,平面向量场图 [x, y, z] = peaks(20); [u, v] = gradient(z); contour(x, y, z, 10); hold on, quiver(x,y ...