JavaScript自学Day8-DOM事件基础

120 阅读3分钟

日期:2023-04-06 学习目标:掌握事件绑定处理和事件对象,完成常见网页交互

1. 事件监听(绑定)

1.1 什么是事件

事件是在编程时系统内发生的动作或者发生的事情,比如用户在网页上单击一个按钮

1.2 什么是事件监听

就是让程序检测是否有事件产生,一旦有事件触发,就立即调用一个函数做出响应,也称为绑定事件或者注册事件,比如鼠标经过显示下拉菜单,比如点击可以播放轮播图等等

1.3 事件监听用法

语法:

元素对象.addEventListener('事件类型',要执行的函数)

事件监听三要素: 事件源:哪个dom元素被时间触发了,要获取dom元素 事件类型:用什么方式触发,比如鼠标单击click、鼠标经过mouseover等 事件调用的函数:要做什么事

例:

    <button>点击</button>
    <script>
        const btn = document.querySelector('button')
        btn.addEventListener('click',function(){
            alert('你点击了~')
        })
    </script>

注意:

  1. 事件类型要加引号
  2. 函数是点击之后再去执行,每次点击都会执行一次

案例:关闭广告

<!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>
        .box{
            width: 800px;
            height: 200px;
            background: #008c8c;
            margin: 0 auto;
            text-align: center;
            line-height: 200px;
            font-size: 2em;
        }
        .box .close-box{
            width: 20px;
            height: 20px;
            background: red;
            float: right;
            text-align: center;
            cursor: pointer;
            line-height: 20px;
            font-size: 0.5em;
        }
    </style>
</head>
<body>
    <div class="box">
        这是一条广告
        <div class="close-box">X</div>
    </div>
    <script>
        const closeBox = document.querySelector('.close-box')
        const box = document.querySelector('.box')
        closeBox.addEventListener('click',function(){
            box.style.display = 'none'
        })
    </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>
    <style>
        .box {
            position: relative;
            width: 500px;
            height: 200px;
            background: #008c8c;
            text-align: center;
            margin: 0 auto;
        }

        .box .text,.text-name {
            position: absolute;
            top: 50px;
            font-size: 2em;
        }
        .box .text{
            left: 110px;
        }
        .box .text-name{
            left: 290px;
            color: #ff5722;
        }

        .box .begin,
        .ending {
            width: 60px;
            height: 40px;
            position: absolute;
            bottom: 10px;
        }

        .box .begin {
            left: 150px;
        }

        .box .ending {
            right: 150px;
        }
    </style>
</head>

<body>
    <div class="box">
        <div class="text">抽取英雄:</div>
        <div class="text-name">英雄</div>
        <button class="begin">开始</button>
        <button class="ending" disabled>结束</button>
    </div>
    <script>
        const arr = ['吕布', '赵云', '典韦', '关羽', '马超', '张飞', '黄忠', '许褚', '夏侯惇']
        const begin = document.querySelector('.begin')
        const ending = document.querySelector('.ending')
        const textName = document.querySelector('.text-name')
        //设置变量用来获取定时器序号
        let timerId = 0
        //设置变量用来获取随机数的值
        let random = 0
        //点击开始按钮,开始随机
        begin.addEventListener('click',function(){
            //点击开始后禁用开始按钮
            begin.disabled = true
            //点击开始后不禁用结束按钮
            ending.disabled = false
            timerId = setInterval(function(){
            random = parseInt(Math.random() * arr.length)
            textName.innerHTML = arr[random]
        },100)
        //数组中只剩下一个名字时,同时禁用两个按钮
        if(arr.length===1){
                ending.disabled = true
                begin.disabled = true
            }
        })
        //点击结束按钮,停止随机并删除抽中的名字
        ending.addEventListener('click',function(){
            ending.disabled = true
            begin.disabled = false
            clearInterval(timerId)
            arr.splice(random,1)
        })
        
    </script>

</body>

</html>

1.4 事件监听版本

  • DOM L0
    事件源.on事件 = function() { }
  • DOM L2
    事件源.addEventListener(事件, 事件处理函数)
  • 区别:
    on方式会被覆盖,addEventListener方式可绑定多次,拥有事件更多特性,推荐使用

2. 事件类型

2.1 事件类型

事件类型事件释义
鼠标事件click鼠标点击
mouseenter鼠标经过
mouseleave鼠标离开
焦点事件focus获得焦点
blur失去焦点
键盘触发Keydown键盘按下触发
Keyup键盘抬起触发
文本事件input用户输入
<body>
    <div class="box" style="width: 200px;height: 200px;background-color: #008c8c;"></div>
    <script>
        const box = document.querySelector('div')
        box.addEventListener('mouseenter',function () {
            console.log('轻轻的我来了~')
        })
        box.addEventListener('mouseleave',function () {
            console.log('正如我轻轻的走~')
        })
    </script>
</body>

2.2 鼠标事件——轮播图案例

<!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>轮播图点击切换</title>
    <style>
        * {
            box-sizing: border-box;
        }
        .slider {
            width: 560px;
            height: 400px;
            overflow: hidden;
        }
        .slider-wrapper {
            width: 100%;
            height: 320px;
        }
        .slider-wrapper img {
            width: 100%;
            height: 100%;
            display: block;
        }
        .slider-footer {
            height: 80px;
            background-color: rgb(100, 67, 68);
            padding: 12px 12px 0 12px;
            position: relative;
        }
        .slider-footer .toggle {
            position: absolute;
            right: 0;
            top: 12px;
            display: flex;
        }
        .slider-footer .toggle button {
            margin-right: 12px;
            width: 28px;
            height: 28px;
            appearance: none;
            border: none;
            background: rgba(255, 255, 255, 0.1);
            color: #fff;
            border-radius: 4px;
            cursor: pointer;
        }
        .slider-footer .toggle button:hover {
            background: rgba(255, 255, 255, 0.2);
        }
        .slider-footer p {
            margin: 0;
            color: #fff;
            font-size: 18px;
            margin-bottom: 10px;
        }
        .slider-indicator {
            margin: 0;
            padding: 0;
            list-style: none;
            display: flex;
            align-items: center;
        }
        .slider-indicator li {
            width: 8px;
            height: 8px;
            margin: 4px;
            border-radius: 50%;
            background: #fff;
            opacity: 0.4;
            cursor: pointer;
        }
        .slider-indicator li.active {
            width: 12px;
            height: 12px;
            opacity: 1;
        }
    </style>
</head>
<body>
    <div class="slider">
        <div class="slider-wrapper">
            <img src="../img/slider01.jpg"
                alt="" />
        </div>
        <div class="slider-footer">
            <p>对人类来说会不会太超前了?</p>
            <ul class="slider-indicator">
                <li class="active"></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
            </ul>
            <div class="toggle">
                <button class="prev">&lt;</button>
                <button class="next">&gt;</button>
            </div>
        </div>
    </div>
    <script>
        // 1. 初始数据
        const sliderData = [
            { url: '../img/slider01.jpg', title: '对人类来说会不会太超前了?', color: 'rgb(100, 67, 68)' },
            { url: '../img/slider02.jpg', title: '开启剑与雪的黑暗传说!', color: 'rgb(43, 35, 26)' },
            { url: '../img/slider03.jpg', title: '真正的jo厨出现了!', color: 'rgb(36, 31, 33)' },
            { url: '../img/slider04.jpg', title: '李玉刚:让世界通过B站看到东方大国文化', color: 'rgb(139, 98, 66)' },
            { url: '../img/slider05.jpg', title: '快来分享你的寒假日常吧~', color: 'rgb(67, 90, 92)' },
            { url: '../img/slider06.jpg', title: '哔哩哔哩小年YEAH', color: 'rgb(166, 131, 143)' },
            { url: '../img/slider07.jpg', title: '一站式解决你的电脑配置问题!!!', color: 'rgb(53, 29, 25)' },
            { url: '../img/slider08.jpg', title: '谁不想和小猫咪贴贴呢!', color: 'rgb(99, 72, 114)' },
        ]
        //获取DOM元素
        const img = document.querySelector('.slider-wrapper img')
        const p = document.querySelector('.slider-footer p')
        const bgc = document.querySelector('.slider-footer')
        
        //声明 信号量 控制播放第几张图片
        let i = 0

        //点击向右按钮向右切换图片
        const next = document.querySelector('.next')
        next.addEventListener('click', function () {
            i++
            i = i >= sliderData.length ? 0 : i
            genghuan() //声明的一个函数,用于更换图片、文字信息、颜色、选中的小圆点等
        })

        //点击向左按钮向左切换图片
        const prev = document.querySelector('.prev')
        prev.addEventListener('click', function () {
            i--
            i = i < 0 ? sliderData.length - 1 : i
            genghuan()
        })

        //声明一个公共的渲染函数,作为复用,切换图片、信息等
        function genghuan() {
            img.src = sliderData[i].url
            p.innerHTML = sliderData[i].title
            bgc.style.backgroundColor = sliderData[i].color
            document.querySelector('.slider-indicator .active').classList.remove('active')
            document.querySelector(`.slider-indicator li:nth-child(${i + 1})`).classList.add('active')
        }

        //开启定时器,轮播图片
        let n = setInterval(function () {
            next.click()  //利用js自动调用点击事件  click()  一定加小括号以调用函数
        }, 1000)


        //鼠标移入,停止定时器
        const slider = document.querySelector('.slider')
        slider.addEventListener('mouseenter', function () {
            clearInterval(n)
        })

        //鼠标离开,重新开启定时器
        slider.addEventListener('mouseleave', function () {
            //关闭之前的定时器
            if (timerId) clearInterval(timerId)
            //重新开启定时器
            n = setInterval(function () {
            next.click()
        }, 1000)
        })
    </script>
</body>
</html>

2.3 焦点事件——搜索框案例

<!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>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        ul {
            list-style: none;
        }
        .baidu {
            position: relative;
            width: 223px;
            margin: 100px auto;
        }
        .baidu input {
            width: 223px;
            height: 48px;
            padding: 0 10px;
            font-size: 14px;
            line-height: 48px;
            border: 1px solid #e0e0e0;
            outline: none;
        }
        .baidu .search {
            border: 1px solid #ff6700;
        }
        .result-list {
            display: none;
            position: absolute;
            left: 0;
            top: 48px;
            width: 223px;
            border: 1px solid #ff6700;
            border-top: 0;
            background: #fff;
        }
        .result-list a {
            display: block;
            padding: 6px 15px;
            font-size: 12px;
            color: #424242;
            text-decoration: none;
        }
        .result-list a:hover {
            background-color: #eee;
        }
    </style>
</head>
<body>
    <div class="baidu">
        <input type="search"
            placeholder="百度一下,你就知道">
        <ul class="result-list">
            <li><a href="#">震惊!一男子竟……</a></li>
            <li><a href="#">唱、跳、rap、篮球</a></li>
            <li><a href="#">小黑子</a></li>
            <li><a href="#">鸡脚</a></li>
            <li><a href="#">小米手机发烫</a></li>
            <li><a href="#">今天吃什么?</a></li>
            <li><a href="#">空调省电小技巧</a></li>
        </ul>
    </div>
    <script>
      //获取元素
	  const input = document.querySelector('[type=search]')
	  const ul = document.querySelector('.result-list')
	  //触发焦点时显示列表,搜索框变色
	  input.addEventListener('focus',function(){
	  	ul.style.display = 'block'
	  	input.classList.add('search')
	  })
	  //失去焦点时隐藏列表,搜索框恢复颜色
	  input.addEventListener('blur',function(){
	  	ul.style.display = 'none'
	  	input.classList.remove('search')
	  })
    </script>
</body>
</html>

2.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>评论回车发布</title>
    <style>
        .total{
            display: none;
        }
    </style>
</head>
<body>
    <div class="box">
        <textarea id="tx"
            placeholder="发一条友善的评论"
            rows="2"
            maxlength="200"></textarea>
        <button>发布</button>
    </div>
    <div class="total">
        0/200字
    </div>
    <script>
        const tx = document.querySelector('#tx')
        const total = document.querySelector('.total')
        // 1. 当文本域获得了焦点,就让 total 显示出来
        tx.addEventListener('focus', function () {
            total.style.display = 'block'
        })
        // 2. 当文本域失去了焦点,就让 total 隐藏出来
        tx.addEventListener('blur', function () {
            total.style.display = 'none'
        })
        // 3. 检测用户输入
        tx.addEventListener('input', function () {
            // console.log(tx.value.length)  得到输入的长度
            total.innerHTML = `${tx.value.length}/200字`
        })
    </script>
</body>
</html>

3. 事件对象

任意事件类型被触发时与事件相关的信息会被以对象的形式记录下来,我们称这个对象为事件对象。

<body>
  <h3>事件对象</h3>
  <p>任意事件类型被触发时与事件相关的信息会被以对象的形式记录下来,我们称这个对象为事件对象。</p>
  <hr>
  <div class="box"></div>
  <script>
    // 获取 .box 元素
    const box = document.querySelector('.box')

    // 添加事件监听
    box.addEventListener('click', function (e) {
      console.log('任意事件类型被触发后,相关信息会以对象形式被记录下来...');

      // 事件回调函数的第1个参数即所谓的事件对象
      console.log(e)
    })
  </script>
</body>

事件回调函数的【第1个参数】即所谓的事件对象,通常习惯性的将这个对数命名为 eventevev

事件对象中包含的有用信息:

  1. ev.type 当前事件的类型
  2. ev.clientX/Y 光标相对浏览器窗口的位置
  3. ev.offsetX/Y 光标相于当前 DOM 元素的位置

注:在事件回调函数内部通过 window.event 同样可以获取事件对象。

4. 环境对象

能够分析判断函数运行在不同环境中 this 所指代的对象。

环境对象指的是函数内部特殊的变量 this ,它代表着当前函数运行时所处的环境。

<script>
  // 声明函数
  function sayHi() {
    // this 是一个变量
    console.log(this);
  }

  // 声明一个对象
  let user = {
    name: '张三',
    sayHi: sayHi // 此处把 sayHi 函数,赋值给 sayHi 属性
  }
  
  let person = {
    name: '李四',
    sayHi: sayHi
  }

  // 直接调用
  sayHi() // window
  window.sayHi() // window

  // 做为对象方法调用
  user.sayHi()// user
	person.sayHi()// person
</script>

结论:

  1. this 本质上是一个变量,数据类型为对象
  2. 函数的调用方式不同 this 变量的值也不同
  3. 【谁调用 this 就是谁】是判断 this 值的粗略规则
  4. 函数直接调用时实际上 window.sayHi() 所以 this 的值为 window

5. 回调函数

如果将函数 A 做为参数传递给函数 B 时,称函数 A 为回调函数。

<script>
  // 声明 foo 函数
  function foo(arg) {
    console.log(arg);
  }

  // 普通的值做为参数
  foo(10);
  foo('hello world!');
  foo(['html', 'css', 'javascript']);

  function bar() {
    console.log('函数也能当参数...');
  }
  // 函数也可以做为参数!!!!
  foo(bar);
</script>

函数 bar 做参数传给了 foo 函数,bar 就是所谓的回调函数了!!!

间歇函数 setInterval

<script>
	function fn() {
    console.log('我是回调函数...');
  }
  // 调用定时器
  setInterval(fn, 1000);
</script>

fn 函数做为参数传给了 setInterval ,这便是回调函数的实际应用了,结合刚刚学习的函数表达式上述代码还有另一种更常见写法。

<script>
  // 调用定时器,匿名函数做为参数
  setInterval(function () {
    console.log('我是回调函数...');
  }, 1000);
</script>

结论:

  1. 回调函数本质还是函数,只不过把它当成参数使用
  2. 使用匿名函数做为回调函数比较常见