// 处理DOM2级事件绑定的兼容性问题
/**
* @param curEle 绑定的元素
* @param eventType 事件类型
* @param eventFn 事件回调
*/
function bind(curEle, eventType, eventFn) {
// 标准浏览器直接使用
if ("addEventListener" in document) {
curEle.addEventListener(eventType, eventFn, false)
return;
}
// curEle.attachEvent("on"+eventType, eventFn.bind(curEle))
// 解决this问题, 将函数提出 (这里不直接使用Function.prototype.bind也是防止兼容问题)
var tempFn = function () { // 把处理前的标签贴在当前属性上
eventFn.call(curEle);
}
// 存储包装前的, 在移除的时候用到
tempFn.photo = eventFn;
if (!curEle["myBind_" + eventType]) {
// 不存在即赋值为一个数组 由于要存储多个方法, 所以让其值为数组
curEle["myBind_" + eventType] = []
}
// 解决重复问题, 往里面添加的时候, 判断是否已经存在
var ary = curEle["myBind_" + eventType]
for (var i = 0; i < ary.length; i++) {
var cur = ary[i];
if (cur.photo === eventFn) {
// 如果在数组中已经存在的话, 那么就不再需要添加该事件
return;
}
}
ary.push(tempFn)
curEle.attachEvent("on" + eventType, tempFn)
}
function unbind(curEle, eventType, eventFn) {
if ("removeEventListener" in document) {
curEle.removeEventListener(eventType, eventFn, false)
return;
}
// 把包装后的结果取出
var ary = curEle["myBind_" + eventType];
for (var i = 0; i < ary.length; i++) {
if (ary[i].photo === eventFn) {
ary.splice(i, 1);
curEle.detachEvent("on" + eventType, eventFn);
break;
}
}
}
// 三大问题: 顺序 重复 this
// 顺序问题: 不用浏览器自带的事件池, 而是自己模拟标准浏览器的事件池
/**
* 创建事件池 且将元素绑定的方法依次添加到事件池中
* @param curEle
* @param eventType
* @param eventFn
*/
function on(curEle, eventType, eventFn) {
if (!curEle["myEvent" + eventType]) {
curEle["myEvent" + eventType] = [];
}
var ary = curEle["myEvent"]
for (var i = 0; i < ary.length; i++) {
var cur = ary[i];
if (cur === eventFn) {
return;
}
}
ary.push(eventFn)
//执行on的时候 给当前元素绑定点击行为, 当点击的时候 执行run方法
// curEle.addEventListener(eventType, run, false);
bind(curEle, eventType, run);
}
/**
* 在事件池中将一个方法移除
* @param curEle
*/
function off(curEle, eventType, eventFn) {
// 获取自定义事件池
var ary = curEle["myEvent" + eventType]
for (var i = 0; i < ary.length; i++) {
var cur = ary[i]
if (cur === eventFn) {
// ary.splice(i, 1) // 为了防止塌陷问题 不使用splice 需要保留索引以及数组长度和数据位置
ary[i] = null;
break;
}
}
}
// 给当前元素绑定一个run方法, 在run方法中根据自己存储的顺序分别把绑定的方法执行
function run(event) {
// this 指向的是当前点击的元素
var e = event || window.event;
// 获取自己事件池中绑定的方法, 让这些方法执行
var flag = e.target ? true : false;
if (!flag) {
e.target = e.srcElement;
e.pageX = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)
e.pageY = event.clientY + (document.documentElement.scrollTop || document.body.scrollTop)
e.preventDefault = function () {
e.returnValue = false;
}
e.stopPropagation = function () {
e.cancelBubble = true;
}
}
var curEle = e.target
var eventType = e.type;
var ary = curEle["myEvent" + eventType];
for (var i = 0; i < ary.length; i++) {
var tempFn = ary[i];
// 在执行过程中删除一些方法的时候 ary被改变了 里面有null没法执行 但是run的时候索引会出问题
if (typeof tempFn === "function") {
tempFn.call(curEle);
} else {
// 说明当前这一样是null 所以可以被移除
ary.splice(i, 1)
i--;
}
}
}
console