首页 > 前端 > js事件对象

js事件对象

博客好久没更新了,期末考试折腾了一个月,暑假又玩了一星期,是时候回来写文章了嘿嘿。

现在记忆力已经不像儿时那样的强悍了,有些东西还是得老老实实记下来不断温习。

 

一、DOM Event 对象

HTML DOM 事件有多种类型,例如鼠标事件、键盘事件、UI事件、触摸事件等等,详见 MDN Event

每触发一个HTML DOM 事件时,都会产生一个event对象,这个对象记录了所触发事件的信息,例如事件发生的所在元素、事件的类型、事件的状态等等,本文所谈及的就是HTML DOM 的 Event 对象。

 

二、Event对象的几个重要属性/方法

1.type属性

该属性返回触发事件的类型,例如“click”“dblclick”“mouseover”等等:

button.addEventListener("click", function (event) {
    console.log(event.type);
});

addEventListener中传入event对象,当点击button元素时,控制台会输出刚才所触发事件的类型——“click”。

 

2.target属性 和 currentTarget属性

target 属性指向触发事件的元素,而currentTarget指向当前处理事件的元素。在没有冒泡/捕获的情况下两者返回值是相等的,而在用到事件委托的场景时,两者的值就不相等了,例如下面这个例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>The difference between "target" and "currentTarget"</title>
</head>
<body>
 
<ul class="ul">
    <li class="li-1">Li-1</li>
    <li class="li-2">Li-2</li>
    <li class="li-3">Li-3</li>
    <li class="li-4">Li-4</li>
</ul>
  
<script>
    document.getElementsByClassName('ul')[0].addEventListener("click", function (event) {
        console.log(event.target);
        console.log(event.currentTarget);
    });
</script>
</body>
</html>

 

js点击事件绑定在“ul”元素上,当点击“Li-2”元素时,控制台输出的”target”为触发该事件的”li-2″元素,而”currentTarget”为处理这个事件的”ul”元素。

 

3.stopPropagation()方法

该方法会取消进一步的事件冒泡或者捕获,即阻止事件在DOM层次中的传播,看下面这个例子:

document.getElementById('parent').addEventListener("click",function() {
    console.log('parent event');
});
document.getElementById('child').addEventListener("click",function() {
    console.log('child event');
});

上面代码中,子元素和父元素都绑定了事件,当点击“child”元素时,不但会触发“child”元素绑定的事件,还会冒泡触发DOM上一级元素“parent”所绑定的事件,即控制台会先后输出’child event’和’parent event’。

当我们只想触发子元素绑定的事件而不想触发父元素绑定的事件时,可以像下面这样写:

document.getElementById('parent').addEventListener("click",function() {
    console.log('parent event');
});
document.getElementById('child').addEventListener("click",function(event) {
    console.log('child event');
    event.stopPropagation();    //阻止事件向上级DOM冒泡
});

这样,当点击“child”元素时,只触发该元素所绑定的事件,控制台只输出”child event”。

 

三、补充

1.兼容的事件处理对象——EventUtil

由于历史的原因,各浏览器厂商对HTML DOM事件的支持程度和方式有些许差异,而Nicholas C.Zakas在《javascript高级程序设计》中给出了增强版的解决方案:

/** EventUtil
 *============
 *
 * @Author   Nicholas C.Zakas
 * @Website  https://www.nczonline.net/
 * @From     Professional JavaScript for Web Developers
 *
 */
 
var EventUtil = {
 
    addHandler: function (element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
 
    getButton: function (event) {
        if (document.implementation.hasFeature("MouseEvents", "2.0")) {
            return event.button;
        } else {
            switch (event.button) {
                case 0:
                case 1:
                case 3:
                case 5:
                case 7:
                    return 0;
                case 2:
                case 6:
                    return 2;
                case 4:
                    return 1;
            }
        }
    },
 
    getCharCode: function (event) {
        if (typeof event.charCode == "number") {
            return event.charCode;
        } else {
            return event.keyCode;
        }
    },
 
    getClipboardText: function (event) {
        var clipboardData = (event.clipboardData || window.clipboardData);
        return clipboardData.getData("text");
    },
 
    getEvent: function (event) {
        return event ? event : window.event;
    },
 
    getRelatedTarget: function (event) {
        if (event.relatedTarget) {
            return event.relatedTarget;
        } else if (event.toElement) {
            return event.toElement;
        } else if (event.fromElement) {
            return event.fromElement;
        } else {
            return null;
        }
 
    },
 
    getTarget: function (event) {
        return event.target || event.srcElement;
    },
 
    getWheelDelta: function (event) {
        if (event.wheelDelta) {
            return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta);
        } else {
            return -event.detail * 40;
        }
    },
 
    preventDefault: function (event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
 
    removeHandler: function (element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    },
 
    setClipboardText: function (event, value) {
        if (event.clipboardData) {
            event.clipboardData.setData("text/plain", value);
        } else if (window.clipboardData) {
            window.clipboardData.setData("text", value);
        }
    },
 
    stopPropagation: function (event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    }
 
};

 

2.提升性能的方案——事件委托

在Javascript中,每绑定多一个事件都会增加一定内存占用空间,当一个页面绑定的事件达到一定数量时就会导致性能下降。对于页面中需要对多个元素绑定多个事件的情况,可以用事件委托来缓解性能问题,它利用的原理是事件冒泡

例如下面这个例子,设想一个音乐播放器有四个按钮,分别控制“播放音乐”“暂停播放”“播放下一首”“下载歌曲”四个功能,也就是四个不同的元素分别监听四个不同的事件:

<form>
    <input type="button" class="button" id="play" value="播放音乐">
    <input type="button" class="button" id="pause" value="暂停播放">
    <input type="button" class="button" id="next" value="播放下一首">
    <input type="button" class="button" id="download" value="下载歌曲">
</form>

一般的做法是分别给四个按钮分别添加四个点击事件处理程序,但是通过使用事件委托的方法,结合上面的EventUtil,我们可以这样做:

因为无论触发哪个按钮,都会冒泡到四个按钮的父级元素也就是’form’层,所以我们可以指定’form’元素为事件处理程序,通过检测不同的target.id属性来实施相应的行为:

var form = document.getElementsByTagName('form')[0];
EventUtil.addHandler(form, "click", function (event) {
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
    switch (target.id) {
        case "play":
            //执行播放音乐...
            break;
        case "pause":
            //执行暂停音乐...
            break;
        case "next":
            //切到下一首歌...
            break;
        case "download":
            //执行下载歌曲...
            break;
        default:
            break;
    }
});

这样,我们只获取一个DOM元素,只添加一个事件,就能完成四个不同按钮的不同触发事件的绑定,节省了内存开销,也提升了性能。

 

参考:《javascript高级程序设计》


本文标题:js事件对象
转载请注明出处,欢迎分享