JavaScript DOM-Event 事件

181 阅读6分钟

JavaScript DOM-Event 事件

前端 JavaScript DOM 和 BOM 学习目录

1. 认识DOM 和 BOM

2. DOM 操作节点、DOM 操作元素节点

3. DOM 获取任意元素 、节点类型、节点名称属性

4. DOM attribute property style属性 className属性 classList属性 Data

5. DOM 创建元素 移除元素 克隆元素

6. DOM 元素操作 window窗口操作

7. DOM Event事件

8. DOM 常用API事件总结

9. BOM 操作

10. JSON数据操作

DOM-Event 认识事件

首先我们的一个页面的话都是需要进行和用户之间进行交互的,这个交互的过程就需要使用到我们的事件处理来实现

JavaScript 是可以实现针对事件编写对应的处理程序的(handler

我们是可以实现的是将页面中的一些部分,用户进行某种处理后,就执行对应的某种代码功能体

我们的事件实现检测的方式含有:

  1. 在 HTML元素中直接实现监听(不推荐使用) <button onclick="console.log("我被点击了")">按钮1</button>
  2. DOM属性,通过元素的 on 来实现监听
  3. 通过 EventTargrt 对象中的 addEventListener 来实现监听
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<button>按钮1</button>
<button>按钮2</button>
<script>
    // 先实现获取我们的元素
    btn = document.querySelectorAll("button")
​
    // on 的事件监听
    btn[0].onclick = function () {
        console.log("我被点击了...")
    }
​
    btn[1].addEventListener('click', function () {
        console.log("我也被点击了")
    })
</script>
</body>
</html>
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<button>按钮1</button>
<button>按钮2</button>
<script>
    // 先实现获取我们的元素
    btn = document.querySelectorAll("button")
​
    function handlerBtn01 () {
        console.log("我被点击了...")
    }
​
    function handlerBtn02 () {
        console.log("我也被点击了")
    }
    
    // on 的事件监听
    btn[0].onclick = handlerBtn01
​
    btn[1].addEventListener('click', handlerBtn02)
</script>
</body>
</html>

上面的就是我们的两中事件监听的不同的书写方法,一种就是回调函数的书写方式,后面就是我们的通过赋值在进行的我们的操作

addEventListener 可以实现的是我们的多同一个事件添加多个执行的回调函数,同时也可以实现随意的移除的操作

但是使用我们的 on 的监听事件的事件的时候,。就不是十分的好绑定以及移除了

addEventListener 是十分灵活的



DOM-Event 认识事件流

当我们在浏览器中实现点击一个元素的时候,我们点击的不仅仅是元素本身,实现点击的是我们的元素本身以及他的层级式的父元素

只要是含有层级关系,那么就会导致事件的上传,这个就是我们的事件冒泡

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        :root {
            --box-color: skyblue;
            --span-color: red;
        }
​
        body {
            padding: 0;
            margin: 0;
​
            .box {
                width: 200px;
                height: 200px;
                background-color: var(--box-color);
                display: flex;
                justify-content: center;
                align-items: center;
                // 回顾:flex 布局中的任何元素是不会再次区分块级和行内元素的
            }
​
            span {
                height: 100px;
                width: 100px;
                background-color: var(--span-color);
            }
        }
    </style>
</head>
<body>
<div class="box">
    <span></span>
</div><script>
    var divEl = document.querySelector(".box")
    var spanEl = document.querySelector("span")
​
    window.addEventListener("click", () => {
        console.log("页面被点击了...")
    })
​
    divEl.addEventListener('click', function () {
        console.log("div 被点击了...")
    })
​
    spanEl.addEventListener('click', function () {
        console.log("span被点击了..")
    })
​
    /**
     * 这个时候我们就会发现一点,当点击我们的 spanEL 的时候,我们是会触发上面两级事件触发的
     * 当我们实现点击 divEL 的时候,我们就会发现, div 和 window 的事件被触发了
     * 当我们实现点击页面的时候, 就只触发本身,因为上面没有闹大了,哈哈
     */
</script>
</body>
</html>

点击我们的 span 的时候,就会触发本身的事件,以及 divEl 的事件,和我们的 window 的事件

点击我们的 div 的时候,就会触发本身以及 window

点击 window 的时候,就只是触发本身

这个就是我们的事件往上实现传递,这个传递的顺序就是我们的事件流



DOM-Event 事件冒泡和事件捕获

从我们的元素的最内层往上传递的顺序,这个顺序就是我们的 事件冒泡(Event Bubble)

从我们的最外层向最内层实现传递的顺序就是我们的 事件捕获(Event Capture)

我们的一个网页中的默认的事件流是我们的 —— 事件冒泡

但是只不过还是可以通过某种手段实现我么的 —— 事件捕获

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        :root {
            --box-color: skyblue;
            --span-color: red;
        }
​
        body {
            padding: 0;
            margin: 0;
​
            .box {
                width: 200px;
                height: 200px;
                background-color: var(--box-color);
                display: flex;
                justify-content: center;
                align-items: center;
                // 回顾:flex 布局中的任何元素是不会再次区分块级和行内元素的
            }
​
            span {
                height: 100px;
                width: 100px;
                background-color: var(--span-color);
            }
        }
    </style>
</head>
<body>
<div class="box">
    <span></span>
</div><script>
    var divEl = document.querySelector(".box")
    var spanEl = document.querySelector("span")
​
    /**
     * addEventListener
     * @param {string} type 指定事件类型
     * @param {function} listener 就是我们的handler处理事件函数
     * @param {boolean} options 选择我们的事件流模式, 默认是事件冒泡模式,true就是表示事件捕获
     */
    spanEl.addEventListener("click", function (e) {}, true)
</script>
</body>
</html>

注意我们的事件冒泡和事件捕获只是事件流的两种不同表现形式

实现我们的进行添加用户的交互功能的实现的时候,就是使用的是我们的

element.onclick = handler handler 就是用来实现处理用户的事件交互的执行函数的

element.addEventListener(type, handler[, options]) handler 就是回调函数,options 就是实现的用来选择事件流模式的



image-20241102173331359.png



DOM-Event 事件对象常用属性

我们的页面实现一些特定的交互的时候,这些交互的事件就是默认的被浏览器包含在了特定的对象中,这个对象就是 Event 对象

在这个对象中有我们的很多的页面的交互实现

获取我们的事件的信息的时候,我们就是通过的是在进行事件监听的时候,传入一个参数,这个参数就是我们的事件参数

一般的规范化的书写格式就是我们的 event 或者 e

我们是可以通过这个参数来获取很多的信息的

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div class="box">
    <span></span>
</div><script>
​
    var divEl = document.querySelector(".box")
​
    // 开始实现使用我们的事件对象
    // 就是我们的这个函数是可以实现接收一个参数
    divEl.addEventListener("click", function (event) {
        console.log("事件对象内容为: ${event}")
    })
​
</script>
</body>
</html>


event 对象中常使用的属性

属性描述实例
type实现获取事件对应的类型event.type
target当前事件发生的元素event.target
currentTarget当前处理事件的元素event.currentTarget
eventPhase事件所处的阶段event.eventPhase
***offsetXoffsetY***是西安发生在元素内的位置event.offsetY
***clientXclientY***事件发生在客户端的位置event.clientX
***pageXpageY***事件发生在客户端相对于页面的位置event.pageX
***screenXscreenY***事件发生在相对于屏幕的位置event.screenX
divEl.addEventListener("click", function (event) {
    console.log(`事件类型: ${event.type}`)
    console.log(`事件阶段: ${event.eventPhase}`)
})

target : 就是我们发生事件的元素对象,同样可以实现触发该事件的其他元素(事件冒泡)

currentTarget : 就是我们的设置事件的对象,这个是一直不变的



DOM-Event 事件对象常用方法

**event.preventDefault() **实现的是阻止默认行为,就是可以实现的就是我们的阻止浏览器默认行为

**event.stopPropagation() **就是实现的是阻止我们的事件流的继续传递



DOM-Event 事件中的 this

首先我们的函数的调用的时候, this 的指向就是我们的 window 全局对象

当我们的函数在事件处理的时候,this的指向就是我们的该元素,是谁进行的处理我们的 handler,那么我们的 this 就是实现指向谁

同时我们在后面还是会学习一些关于改变 this 指向的方法函数的,这个时候我们的 this 的指向就会人为的发生变动

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div class="box">
    <span></span>
</div><script>
​
    var divEl = document.querySelector(".box")
​
    // 开始实现使用我们的事件对象
    // 就是我们的这个函数是可以实现接收一个参数
    divEl.addEventListener("click", function (event) {
        console.log(this)
        console.log(event.currentTarget)
        console.log(divEl)
        console.log(divEl === this)  // true
    })
​
</script>
</body>
</html>


DOM-Event EventTarget类

首先我们需要注意的是,我们的页面中的所有的类都是继承的是我们的这个类来实现的

继承的好处就是我们的: 可以实现我们的代码的复用率的提高

所以说我们的这个类中具有的所有的方法,在我们的每一个元素中都是可以实现使用的

事实上的话,我们的 window 对象也是继承是我们的 EventTarget 这个类的

EventTarget 就是我们的一个DOM 接口,主要是用于我们的添加、删除、派发Event事件的

方法描述
addEventListener实现的是为某个元素注册某个事件类型以及事件处理函数
removeEventListener实现的是为某个元素移除某个事件以及事件处理函数
dispatchEvent实现的是将某个对象类型派送到 EventTarget 上面实现使用
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: skyblue;
        }
    </style>
</head>
<body>
<div class="box"></div><script>
​
    var divEl = document.querySelector(".box")
​
    // 开始实现使用我们的事件对象
    // 就是我们的这个函数是可以实现接收一个参数
    var foo = function (event) {
        console.log("我被电击了")
    }
    
    divEl.addEventListener("click", foo)
​
    setTimeout(function () {
        divEl.removeEventListener("click", foo)
        alert("事件监听已被移除")}
        , 3000)
​
</script>
</body>
</html>

dispatchEvent 就是实现的是我们的自定义一个事件

dispatchEvent(new Event("juwenzhang"))

element.addEventListener("juwenzhang", handler)

image-20241103001552215.png



DOM-Event 事件委派 event delegation

使用我们的事件委托就是为了解决: 当含有多个元素需要做一些相同的事情的时候,这个时候就可以使用我们的事件委托来实现

提高代码的复用率,就是我们在子类中会发生的相同的事件直接在父类中实现即可,然后通过事件委托来实现委派即可

来一个十分清晰的例子吧:

玩过爬虫的都知道,有时间我们是会对我们的一个端口发送客户端请求,然后获取其返回的数据

但是这个时候,我们实现发送网络请求的时候,多次请求这个时候就会发生自己的 ip地址被封的风险

为了避免这个现象的出现,我们就可以使用代理,使用代理的 ip地址来帮我们发送相应的请求,获取我们的返回数据即可

开始实现我们的最原生的写法

即是说每一个li 都实现监听自己的函数点击事件

<!-- 第一种实现形式, 通过this 实现获取本身元素 -->
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .active {
            color: red;
            font-weight: bold;
            text-decoration: underline;
            cursor: pointer;
            font-size: 20px;
        }
​
        .non-active {
            color: black;
        }
    </style>
</head>
<body>
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
</ul><script>
    var liEls = document.querySelectorAll("li")
​
    for (let item of liEls) {
        console.log(item)
        item.onclick = function () {
            for(let item01 of liEls) {
                try {
                    item01.classList.remove("active")
                } catch (e) {
                    console.log(e)
                } finally {
                    item01.classList.add("non-active")
                }
            }
            this.classList.remove("non-active")
            this.classList.add("active")
        }
    }
</script>
</body>
</html>
<!-- 第二种实现形式,通过 event.currentTarget 获取本身元素 -->
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .active {
            color: red;
            font-weight: bold;
            text-decoration: underline;
            cursor: pointer;
            font-size: 20px;
        }
​
        .non-active {
            color: black;
        }
    </style>
</head>
<body>
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
</ul><script>
    var liEls = document.querySelectorAll("li")
​
    for (let item of liEls) {
        console.log(item)
        item.onclick = function (event) {
            for(let item01 of liEls) {
                try {
                    item01.classList.remove("active")
                } catch (e) {
                    console.log(e)
                } finally {
                    item01.classList.add("non-active")
                }
            }
            event.currentTarget.classList.remove("non-active")
            event.currentTarget.classList.add("active")
        }
    }
</script>
</body>
</html>

使用事件委派来实现

就是通过我们的 ul来实现监听事件

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .active {
            color: red;
            font-weight: bold;
            text-decoration: underline;
            cursor: pointer;
            font-size: 20px;
        }
    </style>
</head>
<body>
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
</ul><script>
    var ulEl = document.querySelector("ul")
​
    ulEl.onclick = function (event) {
        for (var i = 0; i < ulEl.children.length; i++) {
            ulEl.children[i].classList.remove('active')
        }
        if (event.target === event.currentTarget) {
            return
        }
        event.target.classList.add("active")
    }
</script>
</body>
</html>
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div class="box">
    <button>添加</button>
    <button>移除</button>
    <button>搜索</button>
</div><script>
    var divEl = document.querySelector(".box")
​
    divEl.onclick = function (event) {
        if(event.target === event.currentTarget) {
            return
        }
        console.log(`点击了${event.target.textContent}按钮`)
    }
</script>
</body>
</html>


有可能从现在开始,书写的有一些代码使用了 let 或者说 const,从严格意义上来讲,这两个关键字应该出现在 es6 里面出现的

但是为了后期的过渡的实现,我们从现在就开始慢慢转变使用 es6 的一些关键字了

现在的话,我们还是在使用我们的 es5 哟,注意!!!