深入理解DOM中的事件对象

3 篇文章 0 订阅
2 篇文章 0 订阅

1.在触发DOM上的某个事件时,会在事件处理程序函数中会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。先看个例子:

var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
    alert(event.type); //"click"
}
btn.addEventListener("click", function(event) {
    alert(event.type); //"click"
}, false);

event.type属性表示事件类型。
event的属性currentTarget意思是事件处理程序当前正在处理事件的那个元素,target意思是事件的目标。在事件处理程序内部,对象this始终等于currentTarget的值,而target则只包含事件的实际目标。看个例子:

var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
    alert(event.currentTarget === this); //true
    alert(event.target === this); //true
};

把事件处理程序直接指定给目标元素btn,则this、currentTarget和target包含相同的值。如果把事件处理程序注册在btn的父节点上(例如document.body),那么:

document.body.onclick = function(envent) {
    alert(event.currentTarget === document.body); //true
    alert(this === document.body); //true
    alert(event.target === document.getElementById("myBtn")); //true
};

target元素等于btn元素,因为它是click事件真正的目标,由于没有注册事件处理程序,结果click冒泡到document.body上,在那里事件得到了处理。

一个函数处理多个事件:

var btn = document.getElementById("myBtn");
var handler = function(event) {
    switch(event.type) {
        case "click":
            alert("Clicked");
            break;
        case "mouseover":
            event.target.style.backgroundColor = "blue";
            break;
        case "mouseout":
            event.target.style.backgroundColor = "red";
            break;
    }
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;

event有个preventDefault()方法,阻止特定事件的默认行为。

event.stopPropagation()方法用于立即停止事件在DOM层次中的传播,即取消进一步的事件捕获或冒泡。例如:

var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
    alert("Clicked");
    event.stopPropagation();
};
document.body.onclick = function(event) {
    alert("Body Clicked");
};

如果不调用event.stopPropagation(),就会出现两个警告框。可是调用了这个方法后,click事件不会传播到document.body,因此就不会触发这个元素上的onclick事件处理程序。


2.再来看看IE中的事件对象
event对象作为window对象的一个熟悉存在。例子:

var btn = document.getElementById("myBtn");
btn.onclick = function() {
    var event = window.event;
    alert(event.type); //"click"
};
btn.attachEvent("click", function(event) {
    alert(event.type); //"click"
}); //也可以通过window取得event对象

IE中event获取事件目标的属性是srcElement,:

var btn = document.getElementById("myBtn");
btn.onclick = function() {
    var event = window.event;
    alert(event.srcElement === this); //true
};
btn.attachEvent("onclick", function(event) {
    alert(event.srcElement === this); //false
});

因为this对象是根据事件处理程序的作用域确定的,所以上面两个不一样。
event.returnValue属性相当于DOM中的preventDefault()方法,只要将returnValue设置为false,就可以阻止默认行为:

var link = document.getElementById("myLink");
link.onclick = function() {
    window.event.returnValue = false;
} //阻止链接默认行为

event.cancelBubble属性与DOM中的stopPropagation()方法作用相同,都是用来停止事件冒泡的。由于IE不支持事件捕获,因而只能取消事件冒泡,但stopPropagation()可以同时支持事件捕获和冒泡。

var btn = document.getElementById("myBtn");
btn.onclick = function() {
    alert("Clicked");
    window.event.cancelBubble = true;
};
document.body.onclick = function() {
    alert("Body Clicked");
};

将cancelBubble设置为true,就可阻止事件通过冒泡而触发document.body中注册的事件处理程序,只出现一个警告框。


3.跨浏览器的事件对象

var EventUtil = {
    getEvent: function(event) {
        return event ? event : window.event;
    },

    getTarget: function(event) {
        return event.target || event.srcElement;
    },

    preventDefault: fuction(event) {
        if(event.preventDefaule()) {
            event.preventDefaule();
        } else {
            event.returnValue = false;
        }
    },

    stopPropagation: function(event) {
        if(event.stopPropagation()) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    }
};

btn.onclick = function(event) {
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event); //等等
}

4.如果事件处理程序过多,会占用内存,导致性能变差。解决办法是用事件委托。就是制定一个事件处理程序,管理某一类型的所有事件。例如:click事件会一直冒泡到document层次,就是说我们可以为整个页面制定一个onclick事件处理程序,而不必为每个单击的元素分别添加事件处理程序。例如:

<ul id="lists">
    <li id="goSomewhere">Go</li>
    <li id="doSomething">Do</li>
    <li id="sayHi">Hi</li>
</ul>

var item1 = document.getElementById("goSomewhere");
var item2 = document.getElementById("doSomething");
var item3 = document.getElementById("sayHi");

EventUtil.addHandler(item1, "click", function(event) {
    location.href = "http://www.google.com";
});
EventUtil.addHandler(item2, "click", function(event) {
    alert("Me");
});
EventUtil.addHandler(item3, "click", function(event) {
    alert("Hi");
});

如果在一个复杂的web应用程序中都使用这种方式,那就会有无数的代码添加事件处理程序,然而可以 事件委托技术解决,就是在DOM树的尽量最高的层次添加一个事件处理程序:

var list = document.getElementById("lists");
EventUtil.addHandler(list, "click", function(event) {
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);

    switch(target.id) {
        case "goSomewhere":
            location.href = "http://www.google.com";
            break;
        case "doSomething":
            alert("Me");
            break;
        case "sayHi":
            alert("Hi");
            break;
    }
});

把事件委托给目标的父元素或者祖先元素,在ul添加添加一个onclick事件处理程序,由于所有目标元素都是这个元素的子节点,而且他们也会过得一个onclick事件,由于事件会冒泡,所以点击事件最终会被ul元素的处理事件程序处理。采用事件委托技术只添加了一个事件处理程序,占用的内存更少。


移除事件处理程序,在不需要的时候移除,也能提高性能,如果内存中留有那些过时不用的空事件处理程序,会造成内存和性能问题。

我们一般会用removeChild()和replaceChild()方法,但更多的是发生在使用innerHTML替换页面中的某一部分,如果把带有事件处理程序的元素用innerHTML替代原先的内容,那么原先添加到元素中的事件处理程序可能无法被当做垃圾回收。例子:

<div id="myDiv">
    <input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
    var btn = document.getElementById("myBtn");
    btn.onclick = function() {
        //执行某些任务
        document.getElementById("myDiv").innerHTML = "Changing...";
    }
</script>

点击按钮就将按钮移除并替换成一个消息,在开发中很流行,但问题是,当按钮被从页面中移除时,它还带着一个事件处理程序。设置innerHTML可以把按钮移走,但事件处理程序仍然与按钮保持着引用关系,那么有些浏览器可能会把元素对事件处理程序的引用保存在内存中,生成了空事件处理程序,如果你知道某个事件即将被移除,那么最好手工处理:

<div id="myDiv">
    <input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
    var btn = document.getElementById("myBtn");
    btn.onclick = function() {
        //执行某些任务
        btn.onclick = null; //移除事件处理程序
        document.getElementById("myDiv").innerHTML = "Changing...";
    }
</script>
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值