JavaScript学习笔记 06、DOM元素—②事件

举报
长路 发表于 2022/11/28 20:47:30 2022/11/28
【摘要】 文章目录前言一、事件监听1.1、常见的鼠标事件监听1.2、常见的键盘事件监听1.3、常见的表单事件监听1.4、常见的页面事件监听二、事件传播2.1、认识捕获阶段与冒泡阶段2.2、DOM0级事件与DOM2级事件(onXXX、addEventListener())两个级别事件介绍示例测试1、捕获阶段与冒泡阶段(查看其执行顺序)2、DOM0级书写的两个相同事件(后覆盖前,只生效一个)3、DOM2级书写的

@[toc]

前言

本篇博客是关于javascript中事件,若文章中出现相关问题,请指出!

所有博客文件目录索引:博客目录索引(持续更新)

一、事件监听

DOM允许我们书写js代码让HTML元素对事件作出反应!

事件类型:用户网页交互动作;点击元素;鼠标移动到元素上等。

事件监听:让计算机能够发现这个事件发生了,从而来执行一些指定的程序。相关的方法主要有onxxxaddEventListener()两种,两种的区别就是"事件传播"。



1.1、常见的鼠标事件监听

事件介绍

下面所述事件在HTMLElement(可通过getElementById()获取)中可调用,作用于元素节点:

image-20210611151621491

  • 其中onmouseenter不冒泡,onmouseover冒泡。(不冒泡的哪怕是内层事件触发外层也不会进行,e.target指向自己本身)。

说明:下面示例中都有详细的注释说明效果!


案例

需求:将上面的所有事件进行测试。

<style>
    * {
        padding: 0;
        margin: 0;
    }

    div {
        width: 80px;
        height: 80px;
        border: 1px solid #000;
        margin: 10px;
        background-color: red;
    }
</style>

<body>
    <div id="box1">

    </div>

    <script>
        var box1 = document.getElementById("box1");
        //1、onclik事件:鼠标按下及抬起都完成算作一次onlick事件,中途按下不抬起就不触发。
        box1.onclick = function () {
            console.log("1、onlick事件触发!");
        };

        //2、ondblclick:鼠标连续两次点击触发(过程中同样会触发onclick事件)
        box1.ondblclick = function () {
            console.log("2、ondblclick事件触发!");
        };

        //3.1、onmousedown:鼠标按下这个动作就触发(在onmouseup、onclick前)
        box1.onmousedown = function () {
            console.log("3.1、onmousedown事件触发!");
        };

        //3.2、onmouseup:鼠标抬起这个动作触发(在onclick前)
        box1.onmouseup = function () {
            console.log("3.2、onmouseup事件触发!");
        };

        //4、鼠标在某个对象中移动时就会触发(一般会进行连续触发)
        box1.onmousemove = function () {
            console.log("4、onmousemove事件触发!");
        };

        //5.1、onmouseenter:鼠标进入某个对象时
        box1.onmouseenter = function () {
            console.log("5.1、onmouseenter事件触发!");
        }

        //5.2、onmouseenter:鼠标离开某个对象时
        box1.onmouseleave = function () {
            console.log("5.2、onmouseleave事件触发!");
        }

    </script>
</body>

image-20210611153228869



1.2、常见的键盘事件监听

介绍

功能:主要是用于监控键盘的。

image-20210611153336981

说明:其中onkeypress会在onkeydown前执行。onkeydownonkeyup对于系统按钮都可识别。onkeypress对于箭头键(上下左右)、功能按键无法识别!!!


示例

需求:对上述事件进行监听测试。

<body>
    <input type="text" id="myinput">

    <script>
        var myinput = document.getElementById("myinput");
        //1、onkeypress:某个键盘被按下(箭头键与功能键无法识别)
        myinput.onkeypress = function () {
            console.log("1、onkeypress:键盘键按下");
        };

        //2、onkeydown:系统按钮都可识别(在onkeypress前执行)
        myinput.onkeydown = function () {
            console.log("2、onkeydown:键盘键按下(箭头键与功能键可识别)");
        }

        //3、onkeyup:当某个键盘松开(系统按钮都可识别)
        myinput.onkeyup = function () {
            console.log("3、onkeyup:按的键盘键抬起");
        }
    </script>
</body>

实操

1、在输入框中按下键盘键"shift"。

image-20210611154337045

2、按下普通英文字符键"A"

image-20210611154508363



1.3、常见的表单事件监听

介绍

前面四个事件都是作用于表单域;后面两个是作用于表单。

事件名 事件描述
oninput 当输入作用域时
onchange 当用户改变域的内容
onfocus 当某元素获得焦点(如tab键或鼠标点击)
onblur 当某元素失去焦点
onsubmit 当表单被提交(作用于表单)
onreset 当表单被重置(作用于表单)

案例

需求:将上述事件进行测试

<style>
    * {
        padding: 0;
        margin: 0;
    }
</style>

<body>
    <form action="#" id="myform">
        姓名
        <input type="text" name="nameFiled">
        <br />
        性别
        <input type="text" name="SexFiled">
        <br />
        <input type="submit">
        <input type="reset">
    </form>

    <script>
        var myform = document.getElementById("myform");
        var nameFiled = myform.nameFiled;
        //用于测试oninput的执行顺序的
        // myform.onkeyup = function () {
        //     console.log("onkeyup");
        // }

        //1、oninput:输入表单信息(在onkeypress事件后,onkeyup前)
        nameFiled.oninput = function () {
            console.log("1、oninput");
        };

        //2、onchange:输入框中内容改变(失去焦点时会检测是否改变,若是改变就触发)
        nameFiled.onchange = function () {
            console.log("2、onchange");
        };

        //3、onfocus:输入框得到焦点时触发事件
        nameFiled.onfocus = function () {
            console.log("3、onfocus");
        };

        //4、onblur:输入框失去焦点时触发事件
        nameFiled.onblur = function () {
            console.log("4、onblur");
        };

        //5、onsubmit(给表单绑定):点击提交表单按钮(type="submit")时触发
        myform.onsubmit = function () {
            alert("表单被提交!");
        }

        //6、onset(给表单绑定):只要点击重置按钮(type="reset")时就会触发!!!
        myform.onreset = function () {
            console.log("onreset");
        }

    </script>
</body>

image-20210611164104641



1.4、常见的页面事件监听

通过使用window对象来进行调用:

image-20210611164213627



二、事件传播

2.1、认识捕获阶段与冒泡阶段

事件触发时其实会有两个阶段:一个是捕获阶段,另一个是冒泡阶段。(若是内层不添加点击事件,外层有点击事件,此时你点内层外层的单击事件就会由于冒泡也进行触发)

image-20210611221312402

之前学习了onxxx的事件监听,该方式只能够监听冒泡阶段。



2.2、DOM0级事件与DOM2级事件(onXXX、addEventListener())

两个级别事件介绍

DOM0级事件监听:只能够监听冒泡阶段。onxxx形式就是该级事件。

//DOM0级事件
oBox.onclick = function(){
};

DOM2级事件:能够监听捕获阶段与冒泡阶段(设置true或者false来监听)。使用addEventListener()方法,

//第一个参数:不加on的对应事件名
//第二个参数:事件函数
oBox.addEventListener('click',function(){
    //这是事件处理函数
},true);//第三个参数:true为监听捕获节点,false监听冒泡阶段

注意

  1. 最内部元素不再区分捕获和冒泡阶段,会先执行写在前面的监听,然后执行后写的监听。
  2. 如果给元素设置相同的两个或多个同名事件:①DOM0级写法后面写的会覆盖先写的(就后一个生效);②DOM2级会按顺序执行(可执行多个)。③两个级别都写了相同的事件,同样会按照顺序生效(对应级别的根据执行规则)。


示例测试

首先摆好盒子方便之后进行测试:

image-20210611223408085

<style>
    * {
        padding: 0;
        margin: 0;
    }

    div#box3 {
        width: 50px;
        height: 50px;
        border: 1px solid #000;
    }

    div#box2 {
        width: 52px;
        height: 52px;
        padding: 50px;
        border: 1px solid #000;
    }

    div#box1 {
        width: 154px;
        height: 154px;
        padding: 50px;
        border: 1px solid #000;
        margin: 20px auto;
    }
</style>

<body>
    <div id="box1">
        <div id="box2">
            <div id="box3"></div>
        </div>
    </div>
</body>

1、捕获阶段与冒泡阶段(查看其执行顺序)

说明:在这里我们在box3中写了两个相同click的事件(一个是捕获阶段,一个是冒泡阶段),对于同节点相同的事件(两个不同阶段的相同事件)根据书写代码的顺序执行的!

<script>
    //获取到三个指定盒子的节点
    var box1 = document.getElementById("box1");
    var box2 = document.getElementById("box2");
    var box3 = document.getElementById("box3");

    //捕获阶段事件
    box1.addEventListener('click', function () {
        console.log("box1的捕获阶段!");
    }, true);//设置true表示为捕获阶段

    box2.addEventListener('click', function () {
        console.log("box2的捕获阶段!");
    }, true);//设置true表示为捕获阶段

    box3.addEventListener('click', function () {
        console.log("box3的捕获阶段!");
    }, true);//设置true表示为捕获阶段

    //冒泡阶段事件(不同节点的相同事件冒泡阶段顺序不同没有影响)
    box1.onclick = function () {
        console.log("box1的冒泡阶段!");
    }

    box2.onclick = function () {
        console.log("box2的冒泡阶段!");
    }

    box3.onclick = function () {
        console.log("box3的冒泡阶段!");
    }

</script>

效果:点击box3的盒子

image-20210611224051668



2、DOM0级书写的两个相同事件(后覆盖前,只生效一个)

结论:后面书写的会覆盖前面书写的,只生效一个。

<script>
    //获取到三个指定盒子的节点
    var box1 = document.getElementById("box1");
    var box2 = document.getElementById("box2");
    var box3 = document.getElementById("box3");

    //书写两个DOM0级的相同click事件
    box3.onclick = function () {
        console.log("NO1.box3的冒泡阶段!");
    };

    box3.onclick = function () {
        console.log("NO2.box3的冒泡阶段!");
    };

</script>

image-20210611224805859



3、DOM2级书写的两个相同事件(按照顺序执行,生效所有)

结论:DOM2级书写的按照顺序执行,生效所有。(下面两个案例来证明)

案例1:NO1在前,NO2在后

<script>
    //获取到三个指定盒子的节点
    var box1 = document.getElementById("box1");
    var box2 = document.getElementById("box2");
    var box3 = document.getElementById("box3");

    //demo1:NO1在前,NO2在后
    box3.addEventListener('click', function () {
        console.log("NO1.box3的捕获阶段!");
    }, false);//设置false表示捕获阶段

    box3.addEventListener('click', function () {
        console.log("NO2.box3的捕获阶段!");
    }, false);//设置false表示捕获阶段

</script>

image-20210611225131526


案例2:NO2在前,NO1在后

<script>
    //获取到三个指定盒子的节点
    var box1 = document.getElementById("box1");
    var box2 = document.getElementById("box2");
    var box3 = document.getElementById("box3");

    //demo2:NO2在前,NO1在后
    box3.addEventListener('click', function () {
        console.log("NO2.box3的捕获阶段!");
    }, false);//设置false表示捕获阶段

    box3.addEventListener('click', function () {
        console.log("NO1.box3的捕获阶段!");
    }, false);//设置false表示捕获阶段
    
</script>

image-20210611225216174



4、DOM0级与DOM2级同时存在(按照顺序来)

结论:DOM0级与DOM2级同时存在,依旧是按照顺序执行的。(若是相同级别的就会按照对应规则执行,如DOM0级的后面会覆盖前面的)。

<script>
    //获取到三个指定盒子的节点
    var box1 = document.getElementById("box1");
    var box2 = document.getElementById("box2");
    var box3 = document.getElementById("box3");

    //demo2:NO2在前,NO1在后
    box3.addEventListener('click', function () {
        console.log("NO2.box3的捕获阶段!");
    }, false);//设置false表示捕获阶段


    box3.addEventListener('click', function () {
        console.log("NO1.box3的捕获阶段!");
    }, false);//设置false表示捕获阶段


    //书写两个DOM0级的相同click事件
    box3.onclick = function () {
        console.log("NO1.box3的冒泡阶段!");
    };

    box3.onclick = function () {
        console.log("NO2.box3的冒泡阶段!");
    };

</script>

image-20210611225619100



三、事件对象(event,作为事件的参数)

3.1、认识事件对象

事件处理函数提供了一个形式参数,它是一个对象,封装了本次事件的细节,这个参数通常直接用event或者e来进行表示。

  • 这个对象哪里传来的呢?由浏览器或者操作系统来传入对应的事件对象,其中封装了当前事件操作的一些细节。

语法

//直接写入一个形参名称即可,这个e就是这次事件的"事件对象"
节点.onmousemove = function (e) {
    //可通过使用e来获取该事件触发时的一些细节
}


3.2、事件对象属性

鼠标位置(6个)

介绍

属性 属性描述
offsetX 鼠标指针相对于事件源元素的水平坐标
offsetY 鼠标指针相对于事件源元素的垂直坐标
clientX 鼠标指针相对于整张网页的水平坐标
clientY 鼠标指针相对于整张网页的垂直坐标
pageX 鼠标指针相对于浏览器的水平坐标
pageY 鼠标指针相对于浏览器的垂直坐标

注意点:其中对于offsetXoffsetY有些特殊,若是指定盒子进行获取该两个值,一旦其盒子中还有小盒子,将鼠标移动至小盒子中会重新根据这个源元素进行计算水平与垂直坐标。


示例演示

①测试offsetXoffsetY(特殊),需要注意了,若是给大盒子绑定了鼠标移动事件获取x,y坐标,此时该盒子中又有一个小盒子,当鼠标移动到小盒子时,坐标会根据这个小盒子重新进行计算!!!

  • 建议:计算指定盒子的源元素x,y轴位置时,就不要其盒子中存在其他盒子!!!

GIF

②对于client是根据当前屏幕测试x,y轴的;对于page是对于整个网页而言进行测试的!

GIF

源码

<style>
    * {
        padding: 0;
        margin: 0;
        height: 1800px;
    }

    div.box {
        height: 200px;
        width: 200px;
        border: 1px solid #000;
        margin: 150px 50px 10px;
    }

    div.innerBox {
        height: 100px;
        width: 100px;
        background-color: red;
        margin: 30px;
    }
</style>

<body>
    <div class="box" id="box">
        <div class="innerBox"></div>
    </div>

    <div class="box2" id="box2"></div>

    <script>
        var o_box = document.getElementById("box");
        var o2_box = document.getElementById("box2");

        o_box.onmousemove = function (e) {
            o2_box.innerHTML = "offsetX/offsetY:" + e.offsetX + "/" + e.offsetY + "<br/>" +
                "clientX/clientY:" + e.clientX + "/" + e.clientY + "<br/>" +
                "pageX/pageY:" + e.pageX + "/" + e.pageY;
        }

    </script>
</body>


键盘输入的字符码与键码(e.charCode、e.keyCode)

介绍

e.charCode:该属性通常使用于onkeypress事件中,表示用户输入的字符的"字符码"。

e.keyCode:该属性通常用于onkeydown事件(该事件中e.charCode无效)和onkeyup中,表示用户按下的按键的"键码"。

image-20210612145207722

  • 对应字符码(在onkeypress中测试):小写字母为65-90,大写字母为97-122。数字是49-57。
  • 对应键码(在onkeydown中测试):小写字母与大写字母都是65-97。数字是96-105。
  • 共同点:空格、以及其他一些按键。

示例

需求:为一个输入框绑定onkeypress事件监测字符码,绑定onkeydown事件监测键码。

GIF



3.2、事件对象方法

阻止事件产生默认动作(preventDefault(),含2案例)

介绍

每个事件都有其对应的默认效果,例如:

  1. 键盘事件:在输入框中进行输入操作(使用键盘输入),其默认事件就是输入键盘的内容到文本框。
  2. 鼠标事件:进行鼠标滚轮滚动时,页面若是有一定长度就会往下翻。

使用方式e.preventDefault()

用途:对于一些特殊的业务需求,需要阻止事件的"默认动作"。


案例

案例1:制作一个文本框,用户只允许输入小写字母和数字,其他字符输入不到文本框中。

GIF

分析:对于该案例,我们需要使用onkeypress事件,因为其对于功能键是进行忽略的,业务中对于输入数字、小写字母情况进行阻止。

使用阻止方法效果:不允许键盘输入的内容到输入框中。

<body>

    输入框(禁止输入除数字与英文字母):<input type="text" id="myinput">

    <script>

        var myinput = document.getElementById("myinput");

        //需要使用onkeypress事件(其一些功能键不会有效,如删除键这类不需要阻止!)
        myinput.onkeypress = function (e) {
            //数字:48-57;小写字母:97-122
            //非这两种输入情况的阻止默认事件(即输入内容到文本框中)
            if (!(e.charCode >= 48 && e.charCode <= 57 || e.charCode >= 97 && e.charCode <= 122)) {
                e.preventDefault();
            }
        };

    </script>

</body>

案例2:鼠标滚轮事件:当鼠标在盒子中向下滚动时,数字+1,反之,数字-1。

学习知识点:

  • 鼠标滚轮滚动事件:onmousewheel。滚动时,event提供了一个属性deltaY,滚轮向下为正数,滚轮向上为负数。

使用阻止事件效果:防止页面高度过长时鼠标滚动带动向下滚。

GIF

<style>
    * {
        margin: 0;
        padding: 0;
    }

    /* 页面宽度支撑滚动时,在盒子中滚动时页面也会向下滚动 */
    body {
        height: 1000px;
    }

    div.box {
        height: 150px;
        width: 150px;
        border: 1px solid #000;
        background-color: red;
    }

    p {
        position: absolute;
        top: 150px;
        left: 75px;
        margin-left: -15px;
        font-size: 30px;
    }
</style>

<body>
    <div class="box" id="box"></div>
    <p id="mp">0</p>

    <script>
        var mbox = document.getElementById("box");
        var myp = document.getElementById("mp");
        // 获取到p标签中的值
        var m_p = Number(myp.textContent);

        //鼠标滚动事件(chrome有效,firefox无效)
        mbox.onmousewheel = function (e) {
            //在盒子中阻止鼠标滚动的默认事件(页面向下滚动)
            e.preventDefault();

            //滚轮向下滚e.deltaY为正数,向下滚为负数
            if (e.deltaY > 0) {
                m_p++;
            } else {
                m_p--;
            }
            //让p标签获取到该值
            myp.innerText = m_p;
        }

    </script>
</body>


阻止事件传播(e.stopPropagation())

介绍

语法e.stopPropagation()。用来阻止事件继续传播(能够切断事件冒泡与捕获),作用到哪个阶段,其之后的阶段不会生效。

  • 在一些场合,非常有必要切断事件继续传播,否则会造成页面特效显示出bug。

示例

情况一:小盒子点击事件阻止大盒子进行冒泡。

image-20210613091245633

情况二:小盒子点击事件,大盒子的捕获阶段来阻止小盒子进行捕获(及其之后的冒泡一同被截断了)。

image-20210613091335671

<style>
    * {
        margin: 0;
        padding: 0;
    }

    div.innerbox {
        width: 100px;
        height: 100px;
        background-color: red;
    }

    div.box {
        width: 100px;
        height: 100px;
        padding: 60px;
        border: 1px solid #000;
    }
</style>

<body>

    <div class="box" id="box">
        <div class="innerbox" id="innerbox"></div>
    </div>

    <script>
        var m_box = document.getElementById("box");
        var m_innerbox = document.getElementById("innerbox");
        // 阻止冒泡(只冒泡内部盒子,不冒泡到外部盒子)
        // m_innerbox.onclick = function (e) {
        //     //内部盒子进行值冒泡外部事假
        //     e.stopPropagation();
        //     console.log("盒子(里)进行冒泡!");
        // }

        // m_box.onclick = function () {
        //     console.log("盒子(外)进行冒泡!");
        // }

        //阻止捕获传递
        m_box.addEventListener('click', function (e) {
            e.stopPropagation();//此时外部盒子内的捕获以及冒泡都不会进行
            console.log("盒子(外)进行捕获!");
        }, true);

        m_innerbox.addEventListener('click', function () {
            console.log("盒子(内)进行捕获!");
        }, true);

    </script>
</body>


案例

1、上下左右键控制div盒子

<style>
    * {
        padding: 0;
        margin: 0;
    }

    div.box {
        position: absolute;
        top: 200px;
        left: 300px;
        height: 100px;
        width: 100px;
        border: 1px solid #000;
        background-color: orange;
    }

    button {
        position: absolute;
        top: 320px;
        left: 275px;
        width: 200px;
        height: 30px;
        background-color: gold;
    }
</style>

<body>
    <div class="box" id="box"></div>
    <button id="mybutton">点我开始移动盒子(上下左右)</button>

    <script>
        //选中盒子节点
        var m_box = document.getElementById("box");
        var m_button = document.getElementById("mybutton");

        //绑定按钮的单击事件
        m_button.onclick = function () {
            //禁用按钮
            m_button.disabled = true;

            //获取到初始浏览器左边距与上边距
            var l = parseInt(document.defaultView.getComputedStyle(m_box, false).left);
            var t = parseInt(document.defaultView.getComputedStyle(m_box, false).top);

            //为整个文档元素绑定键盘监听事件
            document.onkeydown = function (e) {
                console.log(e.keyCode);
                //左、上、右、下:37,38,39,40
                switch (e.keyCode) {
                    case 37:
                        l -= 10;
                        break;
                    case 38:
                        t -= 10;
                        break;
                    case 39:
                        l += 10;
                        break;
                    case 40:
                        t += 10;
                        break;
                }

                //为盒子节点绑定左、上位置
                m_box.style.left = l + "px";
                m_box.style.top = t + "px";
            }
        };
    </script>
</body>

GIF



2、弹出层的显示与隐藏(使用到阻止事件传播知识点)

案例描述:弹出层原本是隐藏的,有三个事件:①点击按钮,弹出层显示。②点击页面,弹出层隐藏。③点击弹出层不会隐藏。

  • 坑点1:当为按钮以及页面绑定单击事件时,两个部分是内外的,点击按钮时必然会进行事件传播,此时就要给点击按钮事件添加阻止事件传播方法。
  • 坑点2:点击显示的弹出层时,其实也会进行事件传播到页面,导致点击弹出层就会触发页面点击事件,弹出层就会隐藏!所以我们也要在弹出层的点击事件中添加阻止事件传播方法。

GIF

源码:

<style>
    * {
        padding: 0;
        margin: 0;
    }

    div.modal {
        width: 100px;
        height: 100px;
        border: 1px solid #000;
        background-color: blue;
        display: none;
    }
</style>

<body>
    <button id="mybotton">点我显示弹出层</button>
    <div class="modal" id="modal"></div>

    <script>
        var m_button = document.getElementById("mybotton");
        var m_modal = document.getElementById("modal");

        //单击按钮:弹出层隐藏
        m_button.onclick = function (e) {
            e.stopPropagation();
            //隐藏弹出层
            m_modal.style.display = "block";
        }

        //给document(即浏览器)绑定点击事件:弹出层显示
        document.onclick = function () {
            //显示弹出层
            m_modal.style.display = "none";
        }

        //给弹出层绑定点击事件:点击它自己本身时阻止冒泡
        m_modal.onclick = function (e) {
            e.stopPropagation();
        }

    </script>
</body>


四、事件委托

4.1、引出事件委托使用(案例引出)

我们来通过一个案例来引出。

案例描述:准备一个ul列表和一个按钮,点击按钮就会新增li元素到ul中,当我们点击li元素时li元素的颜色变为红色!

思路:①新增按钮绑定单击事件,其中包含创建元素、挂载元素到ul中。②通过使用getElementsByTagName获取到p元素,接着来进行遍历添加点击事件。

GIF

问题描绘

  1. 展示效果来看:添加的li元素点击时并没有出现颜色变红的效果原因是初始化时仅仅是对在dom树上的li元素绑定了单击事件,对于后来新增的li元素并没有绑定。解决方案:在点击添加li元素时绑定单击事件再挂载。
  2. 批量添加事件监听的性能问题:我们是采用遍历的方式来进行添加事件的,相当于每个li都绑定的不同的函数,这些函数本身也会很占内存,并且每一个事件监听都会消耗一定的系统内存,对于批量添加事件导致监听数量太多,内存消耗很大。解决方案:采用事件委托(本质就是通过冒泡阶段原理)。

源码

<body>
    <button id="m_bottom">点我添加li元素</button>
    <ul id="list">
        <li>点我颜色变红(初始挂载)</li>
        <li>点我颜色变红(初始挂载)</li>
        <li>点我颜色变红(初始挂载)</li>
    </ul>

    <script>
        var m_list = document.getElementById("list");
        var m_lis = m_list.getElementsByTagName("li");
        var m_button = document.getElementById("m_bottom");

        //给按钮绑定单击事件:添加li元素
        m_button.onclick = function () {
            var newLi = document.createElement("li");
            newLi.innerText = "点我颜色变红(新挂载)";
            m_list.appendChild(newLi);
        }

        //遍历进行动态绑定
        for (let i = 0; i < m_lis.length; i++) {
            //给每一个li添加单击事件
            m_lis[i].onclick = function (e) {
                // this.style.color = "red";  //this表示本身元素
                //e.currentTarget相当于this本身
                e.currentTarget.style.color = "red";
            };
        }

    </script>

</body>

解决之后添加的元素没有单击事件的情况:

image-20210613102926534

  • 实际上还是通过绑定单击事件的形式来添加事件!我们之后可使用事件委托的形式来进行解决!


4.2、认识事件委托(优化4.1案例)

介绍事件委托

事件委托:本质就是利用事件冒泡机制,将后代元素事件委托给祖先元素。

相关属性:对于事件委托通常使用到e.target属性,即事件源元素。

属性 属性描述
e.target 触发此事件的最早元素,即"事件源元素"
e.currentTarget 事件处理程序附加到的元素

应用场景

  1. 当有大量类似元素需要批量添加事件监听时,使用事件委托可以减少内存开销。
  2. 使用效果:当有动态元素节点上树时,使用事件委托可以让新上树的元素具有事件监听。

案例优化(针对于4.1)

优化方式:(将原本对li数组进行一一遍历以及添加按钮事件中对新增的元素添加点击事件) => 只需要给ul添加一个点击事件,此时若是点击li元素就会冒泡到ul的单击事件就实现了对li元素的效果。(配合使用e.target属性使用)

GIF

<body>
    <button id="m_bottom">点我添加li元素</button>
    <ul id="list">
        <li>点我颜色变红(初始挂载)</li>
        <li>点我颜色变红(初始挂载)</li>
        <li>点我颜色变红(初始挂载)</li>
    </ul>

    <script>
        var m_list = document.getElementById("list");
        var m_button = document.getElementById("m_bottom");

        //给按钮绑定单击事件:添加li元素
        m_button.onclick = function () {
            var newLi = document.createElement("li");
            newLi.innerText = "点我颜色变红(新挂载)";
            m_list.appendChild(newLi);
        }

        //优化位置
        //给ul元素绑定单击事件:利用点击li元素事件冒泡到外部元素ul的点击事件
        m_list.onclick = function (e) {
            //console.log(e.target);
            e.target.style.color = "red";
        }

    </script>

</body>


4.2、注意事项(onmouseenter不冒泡)

介绍

onmouseenteronmouseover事件都表示鼠标进入,但是他们也有着区别:

  • onmouseenter:没有冒泡的过程,那么也就是说使用target时就不会检测到对应的来源(只会指定对应本身的元素)。
  • onmouseover:可以冒泡。

注意点:使用事件委托时一定不要委托不冒泡的事件给祖先元素。


案例:测试onmouseenter与onmouseover

测试一:onmouseenter不冒泡情况,鼠标移入也没有效果。

GIF

测试二:onmouseover冒泡

GIF

测试源码:

<body>
    <button id="m_bottom">点我添加li元素</button>
    <ul id="list">
        <li>点我颜色变红(初始挂载)</li>
        <li>点我颜色变红(初始挂载)</li>
        <li>点我颜色变红(初始挂载)</li>
    </ul>

    <script>
        var m_list = document.getElementById("list");
        var m_lis = m_list.getElementsByTagName("li");
        var m_button = document.getElementById("m_bottom");

        //给按钮绑定单击事件:添加li元素
        m_button.onclick = function () {
            var newLi = document.createElement("li");
            newLi.innerText = "点我颜色变红(新挂载)";
            m_list.appendChild(newLi);
        }

        //测试一:onmouseenter不冒泡,此时target指向自己本身元素
        // m_list.onmouseenter = function (e) {
        //     //console.log(e.target);
        //     console.log(e.target);
        //     e.target.style.backgroundcolor = "red";//尽管target指向元素,但是效果无效(很疑惑)
        // }

        //测试二:onmouseover冒泡
        m_list.onmouseover = function (e) {
            console.log(e.target);
            e.target.style.color = "red";//对应li生效
        }

    </script>

</body>
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。