JS事件详解

目录

一、事件注册

1.1、传统注册方式

1.2、监听注册方式

1.3、两种注册方式比较

二、解绑事件

三、事件流

3.1、事件冒泡

3.2、事件捕获

四、事件对象

五、事件属性

5.1事件目标

5.2、事件委托

六、事件方法

6.1、阻止事件冒泡

6.2、阻止默认行为

6.2.1、阻止链接的默认行为

6.2.2、阻止提交按钮提交表单的默认行为

七、鼠标事件


一、事件注册

给元素添加事件就称之为注册事件,注册事件也叫绑定事件。注册事件有两种方式:
(1) 传统注册方式
(2)监听注册方式

1.1、传统注册方式

传统注册方式是通过为指定事件源绑定回调函数的形式来处理事件,当指定事件触发以后回调函数就会被调用,这样就可以实现页面和用户之间的交互了。
可以通过以下两种方式为一个元素绑定事件处理程序:
(1)通过 HTML 元素指定事件属性来绑定 
<button onclick="console.log('haha,骗你的。。。')">点我有奖</button>

(2)通过DOM对象指定的属性来绑定

    <button id="btn">点我。。</button>
    <script>
        var btn = document.querySelector('#btn');
        btn.onclick = function() {
            console.log('谢谢。。。。')
        };
    </script>

1.2、监听注册方式

另一种方式比较特殊事件注册方式是通过事件监听来注册,称为设置事件监听器,它是 W3C 标准推荐使用的方式。通过 EventTarget.addEventListener() 方法来实现。

EventTarget.addEventListener() 将指定的监听器注册到 eventTarget 上,当该对象触发指定的事件时,指定的回调函数就会被执行。 事件目标可以是一个文档上的元素 Element Document和 Window 或者任何其他支持事件的对象 ( 比如 XMLHttpRequest)
addEventListener() 的工作原理是将实现 EventListener 的函数或对象添加到调用它的EventTarget 上的指定事件类型的事件侦听器列表中。
语法格式:
target.addEventListener(type, listener, useCapture);
参数说明:
(1)type :必须,事件监听的类型,如 click mouseover等;
(2) listener :必须,一个实现了 EventListener 接口的对象,或者是一个函数;
(3) useCapture :可选,表示是冒泡还是捕获。值为 true 表示捕获,否则表示冒泡
示例:
    <button>点击</button>
    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click', function() {
            console.log('大家周末好!');
        });
    </script>

1.3、两种注册方式比较

(1)如果使用传统方式进行注册,当对同一个对象添加相同事件时,后面的事件会覆盖掉前面的事件;如果使用监听方式进行注册,当同一个对象绑定相同多个事件时,这些事件都会被执行。

(2)传统注册方式只能进行冒泡,不能进行捕获;而监听注册方式可以冒泡也可以捕获。

示例:

<button class="btn1">传统注册</button>
<button class="btn2">监听注册</button>

<script>
    var btn1 = document.querySelector('.btn1');
    var btn2 = document.querySelector('.btn2');

    // 传统注册
    btn1.onclick = function () {
        console.log('明天星期一,我们休息,大家可以睡个懒觉,哈哈');
    };
    btn1.onclick = function () {
        console.log('星期二我们继续');
    };

    // 监听注册
    btn2.addEventListener('click', function () {
        console.log('今天星期天,快下课了,哈哈');
    });
    btn2.addEventListener('click', function () {
        console.log('但是还得花时间来消化今天的内容。');
    });
</script>

二、解绑事件

对于传统注册方式,解绑事件的语法为:
eventTarget.事件类型 = null;
对于监听注册方式,解绑事件的语法为:
eventTarget.removeEventListener(type, listener[, useCapture]);
示例:
<button class="btn1">传统注册</button>
    <button class="btn2">监听注册</button>
    <script>
        var btn1 = document.querySelector('.btn1');
        var btn2 = document.querySelector('.btn2');
        // 传统注册
        btn1.onclick = function() {
            console.log('明天星期一,我们休息,大家可以睡个懒觉,哈哈');
        };
        // 解绑事件
        btn1.onclick = null;

        // 监听注册

        /*不能解绑事件
        btn2.addEventListener('click', function () {
            console.log('今天星期天,快下课了,哈哈');
        });
        btn2.removeEventListener('click', function () {
            console.log('我们没有关系了。')
        });*/


        function fn() {
            console.log('今天星期天,快下课了,哈哈');
            btn2.removeEventListener('click', fn);
        }

        btn2.addEventListener('click', fn);
    </script>

注意:

对于传统注册事件的解绑:

(1)将解绑事件写在函数里的任何位置,其注册事件只会执行一次;

(2)将解绑事件写在函数外的注册事件前,解绑事件对其无效;将解绑事件写在函数外的注册事件后,注册事件将不执行。

对于监听注册事件的解绑:

(1)将解绑事件写在函数里的任何位置,其注册事件只会执行一次;

(2)将解绑事件写在函数外,那么注册的事件将无效。

(3)对于监听注册方式的解绑,需要注意事件类型和监听函数必须是相同的,否则解绑无效。

三、事件流

由于在 HTML 中的标签都是相互嵌套的,我们可以将元素想象成一个盒子装一个盒子, document 是最外面的大盒子。当你单击一个 div 时,同时你也单击了 div 的父元素,甚至整个页面。
那么是先执行父元素的单击事件,还是先执行 div 的单击事件 ?
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件流</title>
    <style>
        .outer {
            overflow: hidden;
            width: 300px;
            height: 300px;
            margin: 100px auto;
            background-color: blueviolet;
            text-align: center;
        }
        .inner {
            width: 200px;
            height: 200px;
            margin: 50px;
            background-color: cornflowerblue;
            line-height: 200px;
            color: #fff;
        }
    </style>
</head>
<body>
<div class="outer">
    <div class="inner">内部盒子</div>
</div>
<script>
    var inner = document.querySelector('.inner');
    var outer = document.querySelector('.outer');

    inner.addEventListener('click', function () {
        console.log('inner');
    });
    outer.addEventListener('click', function () {
        console.log('outer');
    });
    // 给 body 添加点击事件
    document.body.addEventListener('click', function () {
        console.log('body');
    });
    // 给 html 添加点击事件
    document.documentElement.addEventListener('click', function () {
        console.log('html');
    });
    // 给 document 添加点击事件
    document.addEventListener('click', function () {
        console.log('document');
    });
    window.addEventListener('click', function () {
        console.log('window');
    });
</script>
</body>
</html>
事件流又称为事件传播,描述的是从页面接收事件的顺序。当事件发生时会在元素节点之间按照 特定 的顺序传播,这个传播过程就叫 DOM 事件流

事件流包括三个阶段:事件 捕获阶段 (capture phase) 、处于 目标阶段 (target phase) 事件冒泡 阶段 (bubbling phase)
(1) 捕获阶段:从不确定事件源到确定事件源依次向下响应。
(2)目标阶段:真正的目标节点正在处理事件的阶段(比如你点击鼠标触发事件的那个节点)。
(3) 冒泡阶段:从明确事件源到不明确的事件源依次向上响应。
小故事: IE (微软公司)提出从目标元素开始向外逐层响应事件,也就是冒泡型事件流;而 Netscape(网景公司)提出从层外向目标元素响应事件,也就是捕获型事件流。最终由W3C 组织根据折中的方式来制定了统一标准 —— 先捕获再冒泡。

 注意:

(1)JavaScript 代码中只能执行捕获或冒泡其中一个阶段,要么冒泡,要么捕获。

(2)onclick attachEvent 方式注册的事件只有冒泡阶段。

(3)addEventListener(type, listener[, useCapture]) 第三个参数为 true 表示捕获阶段,默认空着或者 false 为冒泡阶段。

(4) 有些事件不支持冒泡阶段(常见的几个): blur focus mouseenter mouseleave
load unload resize

3.1、事件冒泡

事件冒泡是从明确的对象向不明确对象传播的事件。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件冒泡</title>
    <style>
        .box {
            width: 200px;
            height: 200px;
            background-color: red;
        }
    </style>
</head>
<body>
<div class="box"></div>
<script>
    var box = document.querySelector('.box')
    box.addEventListener('click', function () {
        console.log("div")
    });
    document.body.addEventListener('click', function () {
        console.log('body');
    });
    document.documentElement.addEventListener('click', function () {
        console.log('html');
    });
</script>
</body>
</html>

运行结果:

 注意:事件冒泡是从目标对象向上传播。

3.2、事件捕获

事件捕获是从不明确对象向目标对象的捕获的过程。
示例:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>事件捕获</title>
    <style>
        .box {
            width: 200px;
            height: 200px;
            background-color: red;
        }
    </style>
</head>

<body>
    <div class="box"></div>
    <script>
        var box = document.querySelector('.box')
        box.addEventListener('click', function() {
            console.log("div")
        }, true);
        document.body.addEventListener('click', function() {
            console.log('body');
        }, true);
        document.documentElement.addEventListener('click', function() {
            console.log('html');
        }, true);
    </script>
</body>

</html>

运行结果:

注意:
(1)要想进行捕获,只能使用事件监听注册方式,不能使用事件传统注册方式;
(2)需要把监听注册方法的第三个参数设置为 true
对于今天的开发来说,我们通常都只会处理冒泡,而不会去处理捕获。

四、事件对象

在触发 DOM 上的某个事件时,会产生一个事件对象 event 。这个对象中包含着所有与事件有关
的信息。包括导致事件的元素,事件的类型以及其他与特定事件相关的信息。
比如:
         鼠标操作导致的事件对象中会包含鼠标位置的信息。
又比如:
         键盘操作导致的事件对象中会包含按下的键有关的信息。
事件发生,系统会自动生成一个事件对象。
获取事件对象是通过一个 形参 来操作的,这个形参可以自己确定,一般用 event e 表示, 形参写在函数的括号内。
注意:
(1) 事件对象只能在处理函数内部访问,处理函数允许结束后该对象自动销毁;
(2) 有兼容问题。
示例:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>事件对象</title>
</head>

<body>
    <ul>
        <li>1</li>
        <li>2</li>
    </ul>
    <script>
        var ul = document.querySelector('ul');
        ul.addEventListener('click', function(event) {
            // 处理兼容性问题
            event = event || window.event;
            console.log(event);
            // 从事件对象 event 中获取目标对象
            console.log(event.target.innerHTML);
        });
    </script>
</body>

</html>

五、事件属性

事件对象常用的属性和方法:

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件对象属性</title>
    <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: #ff6700;
        }
    </style>
</head>
<body>
<div class="box"></div>
<script>
    var box = document.querySelector('.box')
    box.onclick = function (event) {
        event = event || window.event;
        // 1. 获取目标对象
        // 1.1 target 标准
        console.log(event.target)
        // 1.2 srcElement 非标准
        console.log(event.srcElement);
        // 2. 获取事件类型,不带 on
        console.log(event.type);
        // 3. 获取在可视化区域的坐标
        console.log(event.clientX + ', ' + event.clientY);
    };
</script>
</body>
</html>

5.1事件目标

目标对象有 currentTarget target srcElement
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件对象目标</title>
    <style>
        ul,li {
            list-style: none;
        }
        .item {
            width: 100px;
            height: 50px;
            background-color: #ff6700;
            margin: 10px;
            text-align: center;
            line-height: 50px;
            color: white;
        }
    </style>
</head>
<body>
<ul id="box">
    <li class="item">1</li>
    <li class="item">2</li>
</ul>
<script>
    var box = document.querySelector('#box')
    box.onclick = function (event) {
        event = event || window.event;
        console.log(event.target);
        console.log(event.srcElement);
        console.log(event.currentTarget);
        console.log(this);
    };
</script>
</body>
</html>

说明:

(1)currentTarget:返回的是绑定事件的对象

(2)target:返回的是事件的实际目标对象(IE8不支持);

(3) srcElement :返回的是事件的实际目标对象( IE8 支持);
(4) this :返回的 是事件的绑定的元素。
e.targer和this的区别:
(1) this 是事件的绑定的元素,它与 currentTarget 是指向同一个;
(2)e.target 是事件触发的元素

5.2、事件委托

事件委托指将事件统一绑定给元素的共同的祖先元素 ,当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件。
事件委托就是利用冒泡,通过委托可以减少事件绑定的次数,提高程序的性能
优点一:提高程序性能
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>事件委托</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
        
        ul {
            list-style: none;
            overflow: hidden;
            margin-top: 80px;
        }
        
        ul li {
            float: left;
            width: 100px;
            height: 30px;
            text-align: center;
            line-height: 30px;
            color: #fff;
            background-color: #000;
            margin: 0 10px
        }
    </style>
</head>

<body>
    <ul id="box">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
    <script>
        var ul = document.querySelector('#box')
            /*
            var lis = document.querySelectorAll('li')
            for (var i = 0; i < lis.length; i++) {
                lis[i].onmouseover = function () {
                    this.style.backgroundColor = 'blue';
                };
                lis[i].onmouseout = function () {
                    this.style.backgroundColor = 'black';
                };
            }*/

        //利用事件委托
        ul.onmouseover = function(e) {
            console.log(e);
            if (e.target.nodeName.toLowerCase() === 'li') {
                e.target.style.backgroundColor = 'blue';
            }
        };
        ul.onmouseout = function(e) {
            if (e.target.nodeName.toLowerCase() === 'li') {
                e.target.style.backgroundColor = 'black';
            }
        };


    </script>
</body>

</html>
从上面的代码可以发现,当把事件绑定在 ul 上时,减少了一个循环。这样就可以提高程序性能。而把事件绑定在 ul 上的方式就是事件委托。
优点二: 使用事件委托的第二个好处是后续添加的子元素也可以拥有委托事件。
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>事件委托</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
        
        ul {
            list-style: none;
            overflow: hidden;
            margin-top: 80px;
        }
        
        ul li {
            float: left;
            width: 100px;
            height: 30px;
            text-align: center;
            line-height: 30px;
            color: #fff;
            background-color: #000;
            margin: 0 10px
        }
    </style>
</head>

<body>
    <ul id="box">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
    <script>
        var ul = document.querySelector('#box')
            /*
            var lis = document.querySelectorAll('li')
            for (var i = 0; i < lis.length; i++) {
                lis[i].onmouseover = function () {
                    this.style.backgroundColor = 'blue';
                };
                lis[i].onmouseout = function () {
                    this.style.backgroundColor = 'black';
                };
            }*/

        //利用事件委托
        ul.onmouseover = function(e) {
            console.log(e);
            if (e.target.nodeName.toLowerCase() === 'li') {
                e.target.style.backgroundColor = 'blue';
            }
        };
        ul.onmouseout = function(e) {
            if (e.target.nodeName.toLowerCase() === 'li') {
                e.target.style.backgroundColor = 'black';
            }
        };

        var li = document.createElement('li');
        li.innerHTML = '6';
        ul.append(li);
    </script>
</body>

</html>

六、事件方法

6.1、阻止事件冒泡

所谓的冒泡指的就是事件的向上传播,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发。事件冒泡的这一特性有好处,也有坏处。如果不希望发生事件冒泡可以通过事件对象来取消冒泡。
示例:取消冒泡
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>阻止事件冒泡</title>
    <style>
        .outer {
            overflow: hidden;
            width: 300px;
            height: 300px;
            margin: 100px auto;
            background-color: blueviolet;
            text-align: center;
            position: relative;
        }
        .inner {
            width: 200px;
            height: 200px;
            margin: 50px;
            background-color: cornflowerblue;
            line-height: 200px;
            color: #fff;
        }

    </style>
</head>
<body>
<div class="outer">
    <div class="inner">内部盒子</div>
</div>
<script>
    var inner = document.querySelector('.inner');
    var outer = document.querySelector('.outer');
    // 当点击 inner 时,不要触发外部的 div 的点击事件
    inner.onclick = function (event) {
        console.log('inner')
        // 处理兼容性问题
        if (event.stopPropagation()) {
            event.stopPropagation(); // 这个方法早期IE版本不支持
        } else {
            event.cancelBubble = true; // IE支持的
        }
    };
    outer.addEventListener('click', function (event) {
        console.log('outer');
    });

</script>
</body>
</html>
说明:如果不希望冒泡的发,我们可以使用事件对象中的 stopPropagation() 方法来阻止事件冒泡的发生。
在事件对象中除了 stopPropagation() 方法可以阻止事件冒泡外,还有一个方法叫 stopImmediatePropagation() ,它也可以阻止事件冒泡。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>阻止事件冒泡</title>
    <style>
        .outer {
            overflow: hidden;
            width: 300px;
            height: 300px;
            margin: 100px auto;
            background-color: blueviolet;
            text-align: center;
            position: relative;
        }
        .inner {
            width: 200px;
            height: 200px;
            margin: 50px;
            background-color: cornflowerblue;
            line-height: 200px;
            color: #fff;
        }
        .outer a {
            position: absolute;
            bottom: 5px;
            left: 10px;
            color: white;
            text-decoration: none;
        }
    </style>
</head>
<body>
<div class="outer">
    <div class="inner">内部盒子</div>
    <a href="javascript:void(0)">点击</a>
</div>
<script>
    var inner = document.querySelector('.inner');
    var outer = document.querySelector('.outer');
    var a = document.querySelector('a');
    // 当点击 inner 时,不要触发外部的 div 的点击事件
    inner.onclick = function (event) {
        console.log('inner')
        // 处理兼容性问题
        if (event.stopPropagation()) {
            event.stopPropagation(); // 这个方法早期IE版本不支持
        } else {
            event.cancelBubble = true; // IE支持的
        }
    };
    outer.addEventListener('click', function (event) {
        console.log('outer');
    });
    a.addEventListener('click', function (event) {
        console.log('-----')
        //event.stopPropagation();
        event.stopImmediatePropagation();
    });
</script>
</body>
</html>

stopPropagation()与stopImmediatePropagation()

相同点:都能阻止事件冒泡的发生。

区别:

(1)stopPropagation() 方法只能阻止事件冒泡的发生,不能阻止同一个对象的相同事件的执行。

(2) stopImmediatePropagation() 方法既可以阻止事件冒泡的发生,也可以阻止同一个对 象的相同事件的执行。

6.2、阻止默认行为

6.2.1、阻止链接的默认行为

HTML 中很多元素都具有默认行为,例如超链接具有点击后跳转页面的默认行为,提交按钮具 有提高表单的默认行为。如何来阻止这个默认行为呢?
可以通过事件对象中的方法来进行阻止。
    <a href="javascript:void(0)">淘宝</a>
    <a href="javascript:;">腾讯</a>
    <a href="https://www.baidu.com">百度</a>
    <script>
        var as = document.querySelectorAll('a');
        as[2].onclick = function(event) {
            //console.log(event);
            event.preventDefault();
        };
    </script>
说明:对于超链接,我们可以有以上三种方式来阻止链接的默认行为。

6.2.2、阻止提交按钮提交表单的默认行为

    <p>
        <form action="https://www.baidu.com" method="post">
            <input type="text" name="s">
            <input type="submit" value="提供">
        </form>
    </p>
    <script>
        var form = document.querySelector('form');
        form.addEventListener('submit', function(event) {
            event.preventDefault();
        });
    </script>

七、鼠标事件

event 事件对象是事件相关的一系列信息的集合,它可分为鼠标事件对象 MouseEvent 和键盘事件对象 KeyboardEvent

 示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>鼠标事件</title>
    <style>
        *{
            padding: 0;
            margin: 0;
        }
        body {
            height: 2000px;
        }
        .box {
            position: fixed;
            top: 0;
            left: 0;
            width: 300px;
            height: 300px;
            margin: 50px;
            background-color: #ff6700;
        }
    </style>
</head>
<body>
<div class="box"></div>
<script>
    var box = document.querySelector('.box')
    box.addEventListener('click', function (event) {
        event = event || window.event;
        // client 是针对于可视化区域的
        console.log(event.clientX, event.clientY);
        // page 是针对于页面
        console.log(event.pageX, event.pageY)
        // screen 是针对于电脑屏幕
        console.log(event.screenX, event.screenY);
    });
</script>
</body>
</html>

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,点击事件是指用户在网页上点击某个元素时所触发的事件。在JavaScript中,我们可以通过给元素添加点击事件监听器来实现对点击事件的响应。下面是一些关于点击事件详解: 1. 给元素添加点击事件监听器的方法 在JavaScript中,我们可以通过以下两种方法为元素添加点击事件监听器: - 使用HTML的onclick属性 我们可以在HTML标签中使用onclick属性来添加点击事件监听器,例如: ``` <button onclick="myFunction()">Click me</button> ``` 这里的myFunction()就是我们要执行的函数,点击按钮时就会触发该函数。 - 使用JavaScript的addEventListener()方法 我们也可以使用JavaScript的addEventListener()方法来为元素添加点击事件监听器,例如: ``` document.getElementById("myButton").addEventListener("click", myFunction); ``` 这里的myButton是我们要添加监听器的按钮元素的id,myFunction是我们要执行的函数。 2. 点击事件的触发条件 点击事件只有在满足以下两个条件时才会被触发: - 用户单击了鼠标左键 只有在用户单击了鼠标左键时,点击事件才会被触发。如果用户单击了鼠标右键或中键,则不会触发点击事件。 - 鼠标单击的元素上有点击事件监听器 只有在用户单击的元素上有点击事件监听器时,点击事件才会被触发。如果用户单击的元素上没有点击事件监听器,则不会触发点击事件。 3. 点击事件对象 在点击事件触发时,会自动创建一个点击事件对象。我们可以通过该对象来获取一些与点击事件相关的信息,例如: - event.target:获取被点击的元素 - event.clientX和event.clientY:获取鼠标单击位置的横坐标和纵坐标 - event.preventDefault():阻止元素的默认行为(例如,阻止链接跳转或表单提交) 4. 防止重复点击 有时候我们可能会遇到这样的情况:用户在短时间内多次点击同一个按钮,导致按钮的事件被触发多次,从而影响网页的正常运行。为了避免这种情况,我们可以采用以下两种方法: - 在函数中添加一个变量,记录上一次点击事件的时间戳,如果当前时间与上一次点击事件的时间间隔小于某个值,就不执行函数。 - 使用JavaScript的debounce函数,该函数可以延迟函数的执行时间,从而防止过于频繁的触发点击事件。 以上就是关于点击事件的一些详解,希望能对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值