MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

JavaScript事件对象的属性与方法

2023-10-046.1k 阅读

JavaScript事件对象的属性与方法

事件对象概述

在JavaScript中,当一个事件发生时,比如用户点击了一个按钮、在文本框中输入内容或者页面加载完成等,浏览器会创建一个事件对象。这个事件对象包含了与该事件相关的各种信息,例如事件发生的元素、鼠标的位置、键盘按键的状态等等。通过访问事件对象的属性和方法,开发者可以更细致地控制和处理事件。

在事件处理函数中,事件对象通常作为参数传递。例如,对于一个点击事件,我们可以这样定义事件处理函数:

<button id="myButton">点击我</button>
<script>
    const myButton = document.getElementById('myButton');
    myButton.addEventListener('click', function(event) {
        // 这里的event就是事件对象
        console.log('事件发生了');
    });
</script>

事件对象的常用属性

type属性

type属性用于获取事件的类型,比如'click''keydown''load'等。这在处理多种类型事件的同一个函数中非常有用。

<button id="clickButton">点击按钮</button>
<input type="text" id="inputField">
<script>
    const clickButton = document.getElementById('clickButton');
    const inputField = document.getElementById('inputField');

    function handleEvent(event) {
        console.log('事件类型: ', event.type);
    }

    clickButton.addEventListener('click', handleEvent);
    inputField.addEventListener('input', handleEvent);
</script>

在上述代码中,handleEvent函数会打印出不同元素触发的不同类型事件。

target属性

target属性指向触发事件的实际DOM元素。这与currentTarget属性不同,currentTarget指向附加事件监听器的元素。

<div id="outerDiv">
    <button id="innerButton">点击我</button>
</div>
<script>
    const outerDiv = document.getElementById('outerDiv');
    const innerButton = document.getElementById('innerButton');

    outerDiv.addEventListener('click', function(event) {
        console.log('target: ', event.target.id);
        console.log('currentTarget: ', event.currentTarget.id);
    });

    innerButton.addEventListener('click', function(event) {
        console.log('target: ', event.target.id);
        console.log('currentTarget: ', event.currentTarget.id);
    });
</script>

当点击innerButton时,对于outerDiv的点击事件监听器,targetinnerButtonidcurrentTargetouterDivid;对于innerButton自身的点击事件监听器,targetcurrentTarget都是innerButtonid

currentTarget属性

如前所述,currentTarget指向附加事件监听器的元素。这在事件冒泡或捕获过程中确定事件处理的当前元素时很有用。

<ul id="parentList">
    <li>列表项1</li>
    <li>列表项2</li>
    <li>列表项3</li>
</ul>
<script>
    const parentList = document.getElementById('parentList');
    parentList.addEventListener('click', function(event) {
        console.log('currentTarget: ', event.currentTarget.id);
    });
</script>

当点击任何一个列表项时,currentTarget都是parentList,因为事件监听器附加在parentList上。

clientX和clientY属性

clientXclientY属性表示事件发生时鼠标指针在浏览器窗口中的水平和垂直坐标(相对于浏览器窗口左上角)。

<div id="testDiv">在这个区域内点击查看坐标</div>
<script>
    const testDiv = document.getElementById('testDiv');
    testDiv.addEventListener('click', function(event) {
        console.log('clientX: ', event.clientX);
        console.log('clientY: ', event.clientY);
    });
</script>

每次在testDiv内点击,都会在控制台打印出鼠标的坐标。

pageX和pageY属性

pageXpageY属性表示事件发生时鼠标指针在整个文档中的水平和垂直坐标(相对于文档的左上角),考虑了页面滚动的情况。

<div style="height: 1000px;"></div>
<button id="scrollButton">滚动到页面底部</button>
<div id="clickDiv">在这个区域内点击查看坐标</div>
<script>
    const scrollButton = document.getElementById('scrollButton');
    const clickDiv = document.getElementById('clickDiv');

    scrollButton.addEventListener('click', function() {
        window.scrollTo(0, document.body.scrollHeight);
    });

    clickDiv.addEventListener('click', function(event) {
        console.log('pageX: ', event.pageX);
        console.log('pageY: ', event.pageY);
    });
</script>

先点击滚动按钮将页面滚动到页面底部,再点击clickDivpageY会显示相对于文档顶部的坐标,而clientY则只是相对于浏览器窗口可见区域的坐标。

screenX和screenY属性

screenXscreenY属性表示事件发生时鼠标指针在用户屏幕中的水平和垂直坐标(相对于屏幕左上角)。

<button id="screenCoordsButton">点击查看屏幕坐标</button>
<script>
    const screenCoordsButton = document.getElementById('screenCoordsButton');
    screenCoordsButton.addEventListener('click', function(event) {
        console.log('screenX: ', event.screenX);
        console.log('screenY: ', event.screenY);
    });
</script>

点击按钮后,控制台会输出鼠标在屏幕上的坐标,这对于开发需要根据屏幕位置进行特定操作的应用程序很有帮助。

key和keyCode属性

在键盘事件(如keydownkeyup)中,key属性表示按下的键的字符值,而keyCode在旧版本浏览器中用于获取按键的代码值(现在部分浏览器仍支持,但推荐使用code属性)。

<input type="text" id="keyInput">
<script>
    const keyInput = document.getElementById('keyInput');
    keyInput.addEventListener('keydown', function(event) {
        console.log('按下的键: ', event.key);
        console.log('键代码(旧): ', event.keyCode);
    });
</script>

当在输入框中按下一个键时,控制台会输出按下的键的字符值和旧的键代码值。

code属性

code属性表示按下的物理按键,无论键盘布局或当前输入法状态如何。例如,无论Caps Lock是否开启,按下字母A时,key可能是'A''a',但code始终是'KeyA'

<input type="text" id="codeInput">
<script>
    const codeInput = document.getElementById('codeInput');
    codeInput.addEventListener('keydown', function(event) {
        console.log('按下的键: ', event.key);
        console.log('物理按键代码: ', event.code);
    });
</script>

在输入框中输入时,可观察到keycode的不同表现。

which属性

which属性在键盘事件中表示按下的键的Unicode值,在鼠标事件中表示按下的鼠标按钮。在键盘事件中,它类似于keyCode,但兼容性更好。

<input type="text" id="whichInput">
<button id="whichButton">点击查看鼠标按钮</button>
<script>
    const whichInput = document.getElementById('whichInput');
    const whichButton = document.getElementById('whichButton');

    whichInput.addEventListener('keydown', function(event) {
        console.log('按键Unicode值: ', event.which);
    });

    whichButton.addEventListener('click', function(event) {
        console.log('鼠标按钮: ', event.which);
    });
</script>

在输入框中按键或点击按钮,可看到which属性在不同事件中的不同用途。

shiftKey、ctrlKey、altKey和metaKey属性

这些属性表示在事件发生时,Shift、Ctrl、Alt和Meta(在Windows上是Windows键,在Mac上是Command键)键是否被按下,返回布尔值。

<button id="modifierButton">点击并同时按下修饰键</button>
<script>
    const modifierButton = document.getElementById('modifierButton');
    modifierButton.addEventListener('click', function(event) {
        console.log('Shift键按下: ', event.shiftKey);
        console.log('Ctrl键按下: ', event.ctrlKey);
        console.log('Alt键按下: ', event.altKey);
        console.log('Meta键按下: ', event.metaKey);
    });
</script>

点击按钮时,同时按下不同的修饰键,控制台会显示相应的布尔值。

事件对象的常用方法

preventDefault()方法

preventDefault()方法用于阻止事件的默认行为。例如,在链接点击事件中,默认行为是导航到链接的href地址,使用preventDefault()可以阻止这种导航。

<a href="https://www.example.com" id="myLink">点击我</a>
<script>
    const myLink = document.getElementById('myLink');
    myLink.addEventListener('click', function(event) {
        event.preventDefault();
        console.log('链接导航被阻止');
    });
</script>

点击链接后,页面不会导航到https://www.example.com,而是在控制台打印出提示信息。

stopPropagation()方法

stopPropagation()方法用于阻止事件冒泡。事件冒泡是指当一个元素上的事件被触发时,该事件会从最内层的元素开始,依次向外传播到祖先元素。

<div id="outer">
    <div id="middle">
        <div id="inner">点击我</div>
    </div>
</div>
<script>
    const outer = document.getElementById('outer');
    const middle = document.getElementById('middle');
    const inner = document.getElementById('inner');

    outer.addEventListener('click', function() {
        console.log('外层div被点击');
    });

    middle.addEventListener('click', function() {
        console.log('中层div被点击');
    });

    inner.addEventListener('click', function(event) {
        console.log('内层div被点击');
        event.stopPropagation();
    });
</script>

点击inner div时,只会打印出“内层div被点击”,因为stopPropagation()阻止了事件继续冒泡到middleouter div。

stopImmediatePropagation()方法

stopImmediatePropagation()方法不仅阻止事件冒泡,还阻止同一元素上其他事件监听器的执行。

<button id="multiListenerButton">点击我</button>
<script>
    const multiListenerButton = document.getElementById('multiListenerButton');

    multiListenerButton.addEventListener('click', function() {
        console.log('第一个监听器');
    });

    multiListenerButton.addEventListener('click', function(event) {
        console.log('第二个监听器');
        event.stopImmediatePropagation();
    });

    multiListenerButton.addEventListener('click', function() {
        console.log('第三个监听器');
    });
</script>

点击按钮时,只会打印出“第一个监听器”和“第二个监听器”,因为stopImmediatePropagation()阻止了第三个监听器的执行。

composedPath()方法

composedPath()方法返回一个包含触发事件的元素及其祖先元素的数组,反映了事件传播的路径。

<article id="article">
    <section id="section">
        <p id="paragraph">点击我查看路径</p>
    </section>
</article>
<script>
    const paragraph = document.getElementById('paragraph');
    paragraph.addEventListener('click', function(event) {
        const path = event.composedPath();
        path.forEach(function(element, index) {
            console.log(`路径元素 ${index + 1}: ${element.tagName}`);
        });
    });
</script>

点击段落时,控制台会打印出从点击的段落开始到文档根元素的所有元素标签名,展示事件传播路径。

事件对象在不同类型事件中的特性

鼠标事件中的事件对象

在鼠标事件(如clickmousedownmouseupmousemove等)中,除了前面提到的通用属性和方法,还有一些特定的属性。例如,button属性表示按下的鼠标按钮,0表示左键,1表示中键,2表示右键。

<button id="mouseButton">点击鼠标按钮查看信息</button>
<script>
    const mouseButton = document.getElementById('mouseButton');
    mouseButton.addEventListener('mousedown', function(event) {
        let buttonText;
        if (event.button === 0) {
            buttonText = '左键';
        } else if (event.button === 1) {
            buttonText = '中键';
        } else if (event.button === 2) {
            buttonText = '右键';
        }
        console.log('按下的鼠标按钮: ', buttonText);
    });
</script>

在按钮上按下不同鼠标按钮,控制台会输出相应的按钮信息。

键盘事件中的事件对象

键盘事件(如keydownkeyupkeypress)有其独特的属性和行为。keypress事件在按下有字符值的键时触发,而keydownkeyup在任何键按下或释放时触发。

<input type="text" id="keyboardInput">
<script>
    const keyboardInput = document.getElementById('keyboardInput');
    keyboardInput.addEventListener('keydown', function(event) {
        console.log('keydown - 按下的键: ', event.key);
    });
    keyboardInput.addEventListener('keyup', function(event) {
        console.log('keyup - 释放的键: ', event.key);
    });
    keyboardInput.addEventListener('keypress', function(event) {
        console.log('keypress - 输入的字符: ', String.fromCharCode(event.which));
    });
</script>

在输入框中输入字符时,会分别触发keydownkeypresskeyup事件,并在控制台打印相应信息。

表单事件中的事件对象

表单事件(如submitinputchange等)涉及表单元素的交互。在submit事件中,常用preventDefault()来阻止表单的默认提交行为,以便进行自定义的表单验证等操作。

<form id="myForm">
    <input type="text" name="username" required>
    <input type="submit" value="提交">
</form>
<script>
    const myForm = document.getElementById('myForm');
    myForm.addEventListener('submit', function(event) {
        const usernameInput = myForm.elements['username'];
        if (usernameInput.value === '') {
            event.preventDefault();
            console.log('用户名不能为空');
        }
    });
</script>

当提交表单且用户名为空时,preventDefault()会阻止表单提交,并在控制台打印错误信息。

窗口和文档事件中的事件对象

窗口和文档事件(如loadunloadresizescroll等)提供了与浏览器窗口和文档相关的事件处理。在resize事件中,可以通过事件对象获取窗口大小变化后的尺寸。

<script>
    window.addEventListener('resize', function(event) {
        console.log('窗口宽度: ', window.innerWidth);
        console.log('窗口高度: ', window.innerHeight);
    });
</script>

当调整浏览器窗口大小时,控制台会输出窗口的新宽度和高度。

跨浏览器兼容性与注意事项

虽然现代浏览器在事件对象的属性和方法支持上已经较为统一,但仍存在一些兼容性问题需要注意。

旧版本浏览器对属性的支持

例如,keyCode在旧版本浏览器中广泛使用,但现在推荐使用code属性。为了兼容旧浏览器,可以这样处理:

<input type="text" id="compatInput">
<script>
    const compatInput = document.getElementById('compatInput');
    compatInput.addEventListener('keydown', function(event) {
        let keyCodeValue;
        if ('code' in event) {
            keyCodeValue = event.code;
        } else {
            keyCodeValue = event.keyCode;
        }
        console.log('按键代码: ', keyCodeValue);
    });
</script>

这样,在支持code属性的浏览器中使用code,在旧浏览器中使用keyCode

事件捕获与冒泡的兼容性

在一些旧浏览器中,事件捕获和冒泡的实现略有不同。在添加事件监听器时,addEventListener的第三个参数用于指定是否在捕获阶段处理事件(true表示捕获阶段,false表示冒泡阶段,默认false)。但在旧版本IE浏览器中,使用attachEvent方法,且该方法只支持冒泡阶段。为了兼容,可以封装一个函数:

<button id="compatButton">点击测试兼容性</button>
<script>
    function addEvent(element, eventType, handler, useCapture) {
        if (element.addEventListener) {
            element.addEventListener(eventType, handler, useCapture);
        } else if (element.attachEvent) {
            element.attachEvent('on' + eventType, handler);
        }
    }

    const compatButton = document.getElementById('compatButton');
    addEvent(compatButton, 'click', function() {
        console.log('按钮被点击');
    }, false);
</script>

这个函数可以在现代浏览器和旧版本IE浏览器中正确添加事件监听器。

事件对象的传递

在一些旧浏览器中,事件对象可能不会自动作为参数传递给事件处理函数。例如在旧IE浏览器中,需要通过window.event来获取事件对象。可以这样兼容:

<button id="eventObjCompatButton">点击测试事件对象兼容性</button>
<script>
    const eventObjCompatButton = document.getElementById('eventObjCompatButton');
    eventObjCompatButton.onclick = function(event) {
        event = event || window.event;
        console.log('事件对象获取成功');
    };
</script>

这样,在不同浏览器中都能正确获取事件对象。

总结

JavaScript事件对象的属性和方法为开发者提供了强大的事件处理能力。通过深入理解并合理运用这些属性和方法,我们可以实现丰富多样的交互效果,提升用户体验。在实际开发中,需要注意跨浏览器兼容性,确保代码在各种浏览器环境中都能正常运行。无论是简单的按钮点击,还是复杂的表单验证、页面交互,事件对象都扮演着至关重要的角色,是前端开发不可或缺的一部分。