JavaScript之web APIs 事件监听 事件类型 事件对象 环境对象 回调函数

63 阅读2分钟

事件监听

事件:编程系统内发生的动作,如网页上单击一个按钮

事件监听:检测是否有事件触发,有的话立即调用函数做出响应,即绑定事件或注册事件

事件监听三要素:事件源 事件类型 事件调用的函数

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

<!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>
        *{
            margin: 0;
            padding: 0;
        }
        h2{
            text-align: center;
        }
        .box{
            width: 600px;
            margin: 50px auto;
            display: flex;
            font-size: 25px;
            line-height: 40px;
        }
        .qs{
            width: 450px;
            height: 40px;
            color: red;
        }
        .btns{
            text-align: center;
        }
        .btns button{
            width: 120px;
            height: 35px;
            margin: 0 50px;
        }
    </style>
</head>
<body>
    <h2>随机点名</h2>
    <div class="box">
        <span>名字是:</span>
        <div class="qs">这里显示名字</div>
    </div>
    <div class="btns">
        <button class="start">开始</button>
        <button class="end">结束</button>
    </div>

    <script>
        const arr = ['马超', '黄忠', '赵云', '关羽', '张飞']
        //声明全局变量,不然作用域中无法调用
        let timeId = 0
        let random = 0
        const start = document.querySelector('.start')
        start.addEventListener('click',function(){
            timeId = setInterval(function(){ 
            random = parseInt(Math.random()*arr.length)
            const qs = document.querySelector('.qs')
            qs.innerHTML = arr[random]
            //抽出一个少一个,不抽重复人民,最终关闭按钮
            },30)
            if(arr.length ===1){
                // start.disabled = true
                // end.disabled  = true
                start.disabled = end.disabled = true
            }
        })
        
        const end = document.querySelector('.end')
        end.addEventListener('click',function(){
            clearInterval(timeId)
            //数组选中元素不重复,选中后删除,最终数组中仅剩一个元素
            arr.splice(random,1)
            console.log(arr);
        })
    </script>
</body>
</html>

事件类型

鼠标事件 click mouseenter mouseleave

案例 -- 轮播图完整版

<!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-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="./images/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>
                const sliderData = [
                { url: './images/slider01.jpg', title: '对人类来说会不会太超前了?', color: 'rgb(100, 67, 68)' },
                { url: './images/slider02.jpg', title: '开启剑与雪的黑暗传说!', color: 'rgb(43, 35, 26)' },
                { url: './images/slider03.jpg', title: '真正的jo厨出现了!', color: 'rgb(36, 31, 33)' },
                { url: './images/slider04.jpg', title: '李玉刚:让世界通过B站看到东方大国文化', color: 'rgb(139, 98, 66)' },
                { url: './images/slider05.jpg', title: '快来分享你的寒假日常吧~', color: 'rgb(67, 90, 92)' },
                { url: './images/slider06.jpg', title: '哔哩哔哩小年YEAH', color: 'rgb(166, 131, 143)' },
                { url: './images/slider07.jpg', title: '一站式解决你的电脑配置问题!!!', color: 'rgb(53, 29, 25)' },
                { url: './images/slider08.jpg', title: '谁不想和小猫咪贴贴呢!', color: 'rgb(99, 72, 114)' },
            ]

            const img = document.querySelector('.slider-wrapper img')
            const p = document.querySelector('.slider-footer p')
            const footer = document.querySelector('.slider-footer')
            const next = document.querySelector('.next')
            const prev = document.querySelector('.prev')

            //设置自变量起始值
            let i=0
            next.addEventListener('click',function(){
                i++
                //判断条件,图片到最后一张时,变量重置为0
                i = i >= sliderData.length ? 0 : i
                common()
            })

            prev.addEventListener('click',function(){
                i--
                //判断条件,图片第一张往后小于0时,爬到最后一张图片的索引号
                i = i < 0 ? sliderData.length-1 : i
                common()
            })

            // 声明一个函数作为复用 精简代码
            function common(){
                img.src = sliderData[i].url
                p.innerHTML = sliderData[i].title
                footer.style.backgroundColor = sliderData[i].color

                //获取li
                const circle = document.querySelector(`.slider-indicator li:nth-child(${i+1})`)
                //先移除以前的高亮类名active
                // document.querySelector(`.slider-indicator li:nth-child(${i})`).classList.remove('active')
                document.querySelector(`.slider-indicator .active`).classList.remove('active')
                //为当前li添加active
                circle.classList.add('active')
            }

            //定时器自动播放轮播图
            let timeId = setInterval(function(){
                //js调用点击事件 click()
                next.click()
            },1000)

            //鼠标经过轮播图时,图片暂停播放
            const slider = document.querySelector('.slider')
            slider.addEventListener('mouseenter',function(){
                 clearInterval(timeId)
            })

            //鼠标离开图片时,图片继续播放
            slider.addEventListener('mouseleave',function(){
                 clearInterval(timeId)
              timeId = setInterval(function(){
                //js调用点击事件 click()
                   next.click()
              },1000)
            })
            </script>
    </body>

表单焦点事件 focus blur

截屏2023-04-25 16.54.46.png

<!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>手机input框焦点</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
 
        ul {
 
            list-style: none;
        }
 
        .mi {
            position: relative;
            width: 223px;
            margin: 100px auto;
        }
 
        .mi input {
            width: 223px;
            height: 48px;
            padding: 0 10px;
            font-size: 14px;
            line-height: 48px;
            border: 1px solid #e0e0e0;
            outline: none;
        }
 
        .mi .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="mi">
        <input type="search" placeholder="小米笔记本">
        <ul class="result-list">
            <li><a href="#">全部商品</a></li>
            <li><a href="#">小米11</a></li>
            <li><a href="#">小米10S</a></li>
            <li><a href="#">小米笔记本</a></li>
            <li><a href="#">小米手机</a></li>
            <li><a href="#">黑鲨4</a></li>
            <li><a href="#">空调</a></li>
        </ul>
    </div>
    <script>
         const ipt = document.querySelector('[type=search]')
         const result = document.querySelector('.result-list')
         ipt.addEventListener('focus',function(){
             result.style.display = 'block'
             ipt.classList.add('search')
         })
         ipt.addEventListener('blur',function(){
             result.style.display = 'none'
             ipt.classList.remove('search')
         })
    </script>
</body>
 
</html>

键盘事件 keydown keyup

文本事件 input

事件对象

对象里存储了事件触发时的相关信息,如判断用户按下回车键 鼠标点击了哪个元素

获取事件对象

事件监听里的回调函数 第一个参数就是事件对象

一般命名为 event ev e

  元素.addEventListener('click',function(e){
        })

事件对象常用属性

type 获取当前事件类型

clientX/clientY 获取光标相对于浏览器可见窗口左上角的位置

offsetX/offsetY 获取光标相对于当前DOM元素左上角的位置

key 用户按下的键盘值

    <input type="text">
    <script>
        const input = document.querySelector('input')
        input.addEventListener('keyup',function(e){
             if(e.key === 'Enter'){
                alert('敲了回车键')
             }
        })
    </script>

案例 -- 评论回车发布

截屏2023-04-25 18.13.30.png

<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>
    .wrapper {
      min-width: 400px;
      max-width: 800px;
      display: flex;
      justify-content: flex-end;
    }
 
    .avatar {
      width: 48px;
      height: 48px;
      border-radius: 50%;
      overflow: hidden;
      background: url(./images/avatar.jpg) no-repeat center / cover;
      margin-right: 20px;
    }
 
    .wrapper textarea {
      outline: none;
      border-color: transparent;
      resize: none;
      background: #f5f5f5;
      border-radius: 4px;
      flex: 1;
      padding: 10px;
      transition: all 0.5s;
      height: 30px;
    }
     /* focus伪类选择器 */
    .wrapper textarea:focus {
      border-color: #e4e4e4;
      background: #fff;
      height: 50px;
    }
 
    .wrapper button {
      background: #00aeec;
      color: #fff;
      border: none;
      border-radius: 4px;
      margin-left: 10px;
      width: 70px;
      cursor: pointer;
    }
 
    .wrapper .total {
      margin-right: 80px;
      color: #999;
      margin-top: 5px;
      opacity: 0;
      transition: all 0.5s;
    }
 
    .list {
      min-width: 400px;
      max-width: 800px;
      display: flex;
    }
 
    .list .item {
      width: 100%;
      display: flex;
    }
 
    .list .item .info {
      flex: 1;
      border-bottom: 1px dashed #e4e4e4;
      padding-bottom: 10px;
    }
 
    .list .item p {
      margin: 0;
    }
 
    .list .item .name {
      color: #FB7299;
      font-size: 14px;
      font-weight: bold;
    }
 
    .list .item .text {
      color: #333;
      padding: 10px 0;
    }
 
    .list .item .time {
      color: #999;
      font-size: 12px;
    }
  </style>
</head>
 
<body>
  <div class="wrapper">
    <i class="avatar"></i>
    <textarea id="tx" placeholder="发一条友善的评论" rows="2" maxlength="200"></textarea>
    <button>发布</button>
  </div>
  <div class="wrapper">
    <span class="total">0/200字</span>
  </div>
  <div class="list">
    <div class="item" style="display: none;">
      <i class="avatar"></i>
      <div class="info">
        <p class="name">清风徐来</p>
        <p class="text">大家都辛苦啦,感谢各位大大的努力,能圆满完成真是太好了[笑哭][支持]</p>
        <p class="time">2022-10-10 20:29:21</p>
      </div>
    </div>
  </div>
  <script>
    const  tx = document.querySelector('#tx')
    const total = document.querySelector('.total')
    const button = document.querySelector('button')
    const item = document.querySelector('.item')
    const text = document.querySelector('.text')
    tx.addEventListener('focus',function(){
        total.style.opacity = 1
    })
    tx.addEventListener('blur',function(){
        total.style.opacity = 0
    })
    tx.addEventListener('input',function(){
        total.innerHTML = `${tx.value.length}/200字`
    })
   
    tx.addEventListener('keyup',function(e){
        if(e.key === 'Enter'){
            //trim()方法去掉字符串左右两边的空格 
            if(tx.value.trim() !== ''){
            item.style.display = 'block'
            //tx.value文本框获取用户输入内容
            text.innerHTML = tx.value
             }
            //回车结束清空文本域
            tx.value = ''
            total.innerHTML = '0/200字'
        }
       
    })

  </script>
 
</body>
 
</html>

环境对象

函数内部特殊的变量 this,代表当前函数运行时所处的环境

谁调用,this指向谁

直接调用函数,相当于 window.函数(),this指代window

    <button>点击</button>
    <script>
        const btn = document.querySelector('button')
        btn.addEventListener('click',function(){
           //this指向btn
            this.style.color = 'red'
        })
    </script>

回调函数

函数A作为参数传递给函数B时,将函数A成为回调函数

      //回调函数 匿名函数作为回调函数较常见
       btn.addEventListener('click',function(){
        })

案例-- tab栏切换

<!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>tab栏切换</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
 
    .tab {
      width: 590px;
      height: 340px;
      margin: 20px;
      border: 1px solid #e4e4e4;
    }
 
    .tab-nav {
      width: 100%;
      height: 60px;
      line-height: 60px;
      display: flex;
      justify-content: space-between;
    }
 
    .tab-nav h3 {
      font-size: 24px;
      font-weight: normal;
      margin-left: 20px;
    }
 
    .tab-nav ul {
      list-style: none;
      display: flex;
      justify-content: flex-end;
    }
 
    .tab-nav ul li {
      margin: 0 20px;
      font-size: 14px;
    }
 
    .tab-nav ul li a {
      text-decoration: none;
      border-bottom: 2px solid transparent;
      color: #333;
    }
 
    .tab-nav ul li a.active {
      border-color: #e1251b;
      color: #e1251b;
    }
 
    .tab-content {
      padding: 0 16px;
    }
 
    .tab-content .item {
      display: none;
    }
 
    .tab-content .item.active {
      display: block;
    }
  </style>
</head>
 
<body>
  <div class="tab">
    <div class="tab-nav">
      <h3>每日特价</h3>
      <ul>
        <li><a class="active" href="javascript:;">精选</a></li>
        <li><a href="javascript:;">美食</a></li>
        <li><a href="javascript:;">百货</a></li>
        <li><a href="javascript:;">个护</a></li>
        <li><a href="javascript:;">预告</a></li>
      </ul>
    </div>
    <div class="tab-content">
      <div class="item active">1<img src="./images/tab00.png" alt="" /></div>
      <div class="item">2<img src="./images/tab01.png" alt="" /></div>
      <div class="item">3<img src="./images/tab02.png" alt="" /></div>
      <div class="item">4<img src="./images/tab03.png" alt="" /></div>
      <div class="item">5<img src="./images/tab04.png" alt="" /></div>
    </div>
  </div>
  <script>
    // 1. a 模块制作 要给 5个链接绑定鼠标经过事件
    // 1.1 获取 a 元素 
    const as = document.querySelectorAll('.tab-nav a')
    for (let i = 0; i < as.length; i++) {
      // 要给 5个链接绑定鼠标经过事件
      as[i].addEventListener('mouseenter', function () {
        // console.log('鼠标经过')
        // 排他思想  
        // 移除类active
        document.querySelector('.tab-nav .active').classList.remove('active')
        // 添加类 active  this指向当前的那个 a 
        this.classList.add('active')
        // 下面5个大盒子 一一对应  .item 
        document.querySelector('.tab-content .active').classList.remove('active')
        // 对应序号的那个 item 显示 添加 active 类
        document.querySelector(`.tab-content .item:nth-child(${i + 1})`).classList.add('active')
 
      })
    }
  </script>
</body>
 
</html>

案例 -- 全选框勾选所有小复选框

截屏2023-04-26 12.23.42.png

<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;
        }
     
        table {
          border-collapse: collapse;
          border-spacing: 0;
          border: 1px solid #c0c0c0;
          width: 500px;
          margin: 100px auto;
          text-align: center;
        }
     
        th {
          background-color: #09c;
          font: bold 16px "微软雅黑";
          color: #fff;
          height: 24px;
        }
     
        td {
          border: 1px solid #d0d0d0;
          color: #404060;
          padding: 10px;
        }
     
        .allCheck {
          width: 80px;
        }

        /* :checked伪类选择器 针对已选中的复选框 未勾选不做操作 */
        .ck:checked{
            width: 20px;
            height: 20px;
        }
      </style>
    
</head>
<body>
    <table>
        <tr>
          <th class="allCheck">
            <input type="checkbox" name="" id="checkAll"> <span class="all">全选</span>
          </th>
          <th>商品</th>
          <th>商家</th>
          <th>价格</th>
        </tr>
        <tr>
          <td>
            <input type="checkbox" name="check" class="ck">
          </td>
          <td>小米手机</td>
          <td>小米</td>
          <td>¥1999</td>
        </tr>
        <tr>
          <td>
            <input type="checkbox" name="check" class="ck">
          </td>
          <td>小米净水器</td>
          <td>小米</td>
          <td>¥4999</td>
        </tr>
        <tr>
          <td>
            <input type="checkbox" name="check" class="ck">
          </td>
          <td>小米电视</td>
          <td>小米</td>
          <td>¥5999</td>
        </tr>
      </table>
      <script>
        //1.全选框控制小复选框全选或不全选
        //获取全选框
        const ipt = document.querySelector('#checkAll')
        //获取所有小复选框
        const ck = document.querySelectorAll('.ck')
        //点击全选框时所有小复选框与全选框状态一致 checked为false或true
        ipt.addEventListener('click',function(){
            for(let i=0;i<ck.length;i++){
                ck[i].checked = this.checked
            }
        })
       
        // 2.小复选框控制全选框全部选中
        for(let i = 0;i<ck.length;i++){
            ck[i].addEventListener('click',function(){
                //利用:checked伪类选择器 被勾选的复选框的个数 是否等于所有复选框的个数
               const a = document.querySelectorAll('.ck:checked').length
               //结果为true或false 赋值给全选框 
               ipt.checked = a === ck.length
            }) 
        }
      </script>
</body>
</html>