据说每个大牛、小牛都应该有自己的库——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原生对象拓展 在据说每个大牛.小牛都应该有自己的库——框架篇中我扬言要做个小牛,没想到一天没更新,小伙儿伴们就戏谑的问我,油哥是不是要太监了?其实事情是这个样子的,这不是太监的节奏 ...
随机推荐
- Clone
Clone: 构建一个对象的时候,是不是一定要调用构造函数! package com.edu.test; public class Zhenzhen implements Cloneable{ pub ...
- 用Backbone.js创建一个联系人管理系统(五)
原文: Build a Contacts Manager Using Backbone.js: Part 5 这是这系列教程最后一部分了. 之前所有的增删改都在前端完成. 这部分我们要把Contact ...
- EM最大期望化算法
最大期望算法(Expectation-maximization algorithm,又译期望最大化算法)在统计中被用于寻找,依赖于不可观察的隐性变量的概率模型中,参数的最大似然估计. 在统计计算中,最 ...
- LeetCode OJ-- 二战 Palindrome Number
判断一个 int 是否为回文的 有一点要注意的是: int x; int _x = abs(x); 对 x 取绝对值的时候,会发生溢出.比如 x = INT_MIN 即 -2147483648 而 ...
- Qt MVC(模型-视图-代理)
实习刚才是一段时间,公司这边就要求熟悉这个mvc.一般开始都是用tableview,前面的blog我都是使用listview居多,并且相对delegate这个使用的多余model.接下来说下model ...
- yii使用createCommand()增删改查
查询单条数据$sql = "SELECT `name` FROM `table` WHERE id='7'";$users=Yii::$app->db->createC ...
- win使用MSYS2安装Qt开发环境
原文链接 MSYS2 下载地址: pacman的具体用法 有pacman的具体使用方法.我们首先对系统升级 我们首先对系统升级 pacman -Syu 就会检测整个系统可以升级的组件,并自动下载安装, ...
- json_encode中文unicode的问题
近期做微信卡券开发遇到一个问题,创建卡券post数据给服务器时返回data format error, do NOT use json unicode encode (/uxxxx/uxxxx), p ...
- Redis多机常用架构-主从
本文内容摘录自同事Perry Zhang的讲解,如需转载须本人同意. 1.主从 命令:slaveof <IP><PORT> redis主从配置:redis支持master-sl ...
- IIS出现问题时修改配置文件的几项说明
近期系统在线运行经常出现object moved错误 通过查询资料,做了几项web.config文件的调整 1,调整应用程序池使用集成模式 <system.webServer> ...