js:事件对象+事件流+事件委托

130 阅读4分钟

事件对象

也是个对象,这个对象里有事件触发时的相关信息 例如:鼠标点击事件中,事件对象就存了鼠标点在哪个位置等信息

获取事件对象

在事件绑定的回调函数的第一个参数就是事件对象 一般命名为event、ev、e

1649944969377

事件对象常用属性

  1. type 获取当前的事件类型
 let div = document.querySelector('div');
        div.addEventListener('click', function(e) {
            //输出为 click
            console.log(e.type);

        })
  1. clientX/clientY 获取光标相对于浏览器可见窗口左上角的位置
   div.addEventListener('click', function(e) {
            //相距浏览器左边,上边的距离
            console.log(e.clientX, e.clientY);
        })
  1. offsetX/offsetY 获取光标相对于当前DOM元素左上角的位置
   let div = document.querySelector('div');

        div.addEventListener('click', function(e) {
            //相距dom元素左边,上边的距离
            console.log(e.offsetX, e.offsetY);
        })
  1. key 用户按下的键盘键的值 现在不提倡使用keyCode
  window.addEventListener('keydown', function(e) {
            //获取键盘的值 例如按下 enter键,值为Enter
            console.log(e.key);

        })

鼠标跟随案例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        img {
            position: absolute;
            /* 移动自身宽高的一半,此时鼠标在图片垂直居中位置 */
            transform: translate(-50%, -50%);
        }
        
        body {
            height: 100vh;
            overflow: hidden;
            /*  隐藏鼠标 */
            cursor: none;
        }
    </style>
</head>

<body>
    <img src="./images/天使.gif" alt="">
    <script>
        const img = document.querySelector('img');
        document.body.addEventListener('mousemove', function(e) {
            //图片的坐标和鼠标在浏览器的位置相等
            img.style.left = e.clientX + 'px';
            img.style.top = e.clientY + 'px';
        })
    </script>
</body>

</html>

回车发布微博案例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <textarea cols="30" rows="10"></textarea>
    <button>发布</button>
    <h1></h1>
    <script>
        let text = document.querySelector('textarea'),
            btn = document.querySelector('button'),
            h1 = document.querySelector('h1');

        btn.addEventListener('click', function(e) {

            //trim()方法是给字符串前后去掉空白符
            if (text.value.trim() === '') {
                return;
            }
            h1.innerHTML = text.value;
        })
        text.addEventListener('keydown', function(e) {
            //e.key返回的值是字符串
            if (e.key === 'Enter') {
                btn.click();
                //按下回车键不换行,取消文本域的默认行为
                // e.preventDefault();
            }

        })
    </script>

</body>

</html>

事件流

事件流指的是事件完整执行过程中的流动路径

1650118146124

说明:假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段 简单来说:捕获阶段是 从父到子 冒泡阶段是从子到父

事件冒泡

当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。这一过程被称为事件冒泡。

  1. 简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的同名事件
  2. 事件冒泡是默认存在的

1650118222607

事件捕获

从DOM的根元素开始去执行对应的事件 (从外到里)

代码:

1650118296519

说明:

  1. addEventListener第三个参数传入true代表是捕获阶段触发(很少使用)
  2. 若传入false代表冒泡阶段触发,默认就是false
  3. 若是用 L0 事件监听,则只有冒泡阶段,没有捕获

阻止事件流动

  1. 因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素
  2. 若想把事件就限制在当前元素内,就需要阻止事件流动
  3. 阻止事件流动需要拿到事件对象

语法:

1650118420904

此方法可以阻断事件流动传播,不光在冒泡阶段有效,捕获阶段也有效。

鼠标经过事件

  1. mouseover 和 mouseout 会有冒泡效果
  2. mouseenter 和 mouseleave 没有冒泡效果(推荐)

阻止默认行为

比如链接点击不跳转,表单域的不提交

语法:

1650118834096

代码:

1650118852759

两种注册事件的区别:

传统on注册(L0)

  1. 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)
  2. 直接使用null覆盖就可以实现事件的解绑
  3. 都是冒泡阶段执行的

事件监听注册(L2)

语法: addEventListener(事件类型, 事件处理函数, 是否使用捕获)

  1. 后面注册的事件不会覆盖前面注册的事件(同一个事件)
  2. 可以通过第三个参数去确定是在冒泡或者捕获阶段执行
  3. 必须使用removeEventListener(事件类型, 事件处理函数, 获取捕获或者冒泡阶段)
  4. 匿名函数无法被解绑

冒泡事件解除绑定案例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button>点击</button>
    <script>
        const btn = document.querySelector('button');

        function getNu() {
            document.body.style.backgroundColor = 'blue';
        }

        function getNum() {
            console.log('111');
        }
        btn.addEventListener('click', getNu);
        btn.addEventListener('click', getNum);
        //解除绑定事件和业务逻辑,只解除了一个事件和一个业务逻辑
        btn.removeEventListener('click', getNum);
    </script>
</body>

</html>

事件委托

事件委托是利用事件流的特征解决一些开发需求的知识技巧

总结: 优点:给父级元素加事件(可以提高性能) 原理:事件委托其实是利用事件冒泡的特点, 给父元素添加事件,子元素可以触发 实现:事件对象.target 可以获得真正触发事件的元素

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
            box-sizing: border-box;
        }
        
        body {
            height: 100vh;
        }
        
        ul {
            width: 100px;
            height: 95px;
            padding: 0px 10px;
            border: 1px solid black;
            list-style-type: none;
            border-radius: 10px;
        }
        
        li {
            padding: 5px 0px;
            cursor: pointer;
        }
    </style>

</head>

<body>
    <ul>
        <li>回到首页</li>
        <li>到达底部</li>
        <li>刷新</li>
    </ul>
    <script>
         let ul = document.querySelector('ul');
         ul.addEventListener('click', function(e) {
         e.target.style.backgroundColor = 'red';
        })
    </script>
</body>

</html>

获取当前事件触发的dom元素名称

语法:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
            box-sizing: border-box;
        }
        
        body {
            height: 100vh;
        }
        
        ul {
            width: 100px;
            height: 95px;
            padding: 0px 10px;
            border: 1px solid black;
            list-style-type: none;
            border-radius: 10px;
        }
        
        li {
            padding: 5px 0px;
            cursor: pointer;
        }
    </style>

</head>

<body>
    <ul>
        <li>回到首页</li>
        <li>到达底部</li>
        <li>刷新</li>
    </ul>
    <script>
       
        let ul = document.querySelector('ul');
        ul.addEventListener('click', function(e) {
            console.log(e.target.nodeName);//输出LI
       
        })
    </script>
</body>

</html>

渲染学生信息案例

数据驱动视图

需求:点击录入按钮,可以增加学生信息

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>08-综合案例-模版</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        
        a {
            text-decoration: none;
            color: #721c24;
        }
        
        h1 {
            text-align: center;
            color: #333;
            margin: 20px 0;
        }
        
        table {
            margin: 0 auto;
            width: 800px;
            border-collapse: collapse;
            color: #004085;
        }
        
        th {
            padding: 10px;
            background: #cfe5ff;
            font-size: 20px;
            font-weight: 400;
        }
        
        td,
        th {
            border: 1px solid #b8daff;
        }
        
        td {
            padding: 10px;
            color: #666;
            text-align: center;
            font-size: 16px;
        }
        
        tbody tr {
            background: #fff;
        }
        
        tbody tr:hover {
            background: #e1ecf8;
        }
        
        .info {
            width: 900px;
            margin: 50px auto;
            text-align: center;
        }
        
        .info input {
            width: 80px;
            height: 25px;
            outline: none;
            border-radius: 5px;
            border: 1px solid #b8daff;
            padding-left: 5px;
        }
        
        .info button {
            width: 60px;
            height: 25px;
            background-color: #004085;
            outline: none;
            border: 0;
            color: #fff;
            cursor: pointer;
            border-radius: 5px;
        }
        
        .info .age {
            width: 50px;
        }
    </style>
</head>

<body>
    <h1>新增学员</h1>
    <div class="info">
        姓名:<input type="text" class="uname" /> 年龄:<input type="text" class="age" /> 性别:
        <select name="gender" id="" class="gender">
        <option value="男"></option>
        <option value="女"></option>
      </select> 薪资:
        <input type="text" class="salary" /> 就业城市:<select name="city" id="" class="city">
        <option value="北京">北京</option>
        <option value="上海">上海</option>
        <option value="广州">广州</option>
        <option value="深圳">深圳</option>
        <option value="曹县">曹县</option>
      </select>
        <button class="add">录入</button>
    </div>

    <h1>就业榜</h1>
    <table>
        <thead>
            <tr>
                <th>学号</th>
                <th>姓名</th>
                <th>年龄</th>
                <th>性别</th>
                <th>薪资</th>
                <th>就业城市</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <!-- <tr>
          <td>1</td>
          <td>这是名称</td>
          <td>这是年龄</td>
          <td>这是性别</td>
          <td>这是工资</td>
          <td>这是所在城市</td>
          <td>
            <a href="javascript:" class="del">删除</a>
          </td>
        </tr> -->
        </tbody>
    </table>
    <script>
        let arr = [];
        const tbody = document.querySelector('tbody'),
            add = document.querySelector('.add'),
            uname = document.querySelector('.uname'),
            age = document.querySelector('.age'),
            gender = document.querySelector('.gender'),
            salary = document.querySelector('.salary'),
            city = document.querySelector('.city');
        //创建数组的对象
        add.addEventListener('click', function() {
            const Obj = {
                    id: Date.now(),
                    uname: uname.value,
                    age: age.value,
                    gender: gender.value,
                    salary: salary.value,
                    city: city.value
                }
                //将对象推进arr数组里
            arr.push(Obj); //此时输出的是数组的长度
            //对象传入后刷新数据,将数据传入表格中
            getTr();
            uname.value = '';
            age.value = '';
            gender.value = '男';
            salary.value = '';
            city.value = '北京';
        })

        tbody.addEventListener('click', function(e) {

                if (e.target.nodeName === 'A') {
                    let num = e.target.dataset.num;
                    arr.splice(num, 1)
                }
                getTr()
            })
            //封装创建tbody里的标签功能
        function getTr() {
            let html = '';
            for (let i = 0; i < arr.length; i++) {
                html += ` 
                <tr>
          <td>${arr[i].id}</td>
          <td>${arr[i].uname}</td>
          <td>${arr[i].age}</td>
          <td>${arr[i].gender}</td>
          <td>${arr[i].salary}</td>
          <td>${arr[i].city}</td>
          <td>
            <a href="javascript:" class="del" data-num=${i}>删除</a>
          </td>
        </tr> `
            }
            tbody.innerHTML = html;
        }
    </script>
</body>

</html>