WEB APIS知识点案例总结

本文围绕前端开发,以JavaScript为核心,介绍多个案例。包括随机点名、轮播图切换、小米搜索框等。详细讲解事件监听、事件类型(鼠标、焦点、键盘等)、事件对象、事件流(捕获、冒泡)、注册事件区别、事件委托等知识,还提及阻止默认行为等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

随机点名案例

业务分析:

  1. 点击开始按钮随机抽取数组中的一个数据,放到页面中
  2. 点击结束按钮删除数组当前抽取的一个数据
  3. 当抽取到最后一个数据的时候,两个按钮同时禁用(只剩最后一个数据不用抽了)

核心:利用定时器快速展示,停止定时器结束展示 

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</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 = ['马超', '黄忠', '赵云', '关羽', '张飞']
        const qs=document.querySelector('.qs')
        //  业务1. 开始按钮模块
        // 1.1 获取开始按钮对象\
        let timerId=0
        let random=0
        const start =document.querySelector('.start')
        //1.2添加点击事件
        start.addEventListener('click',function(){
            timerId =setInterval(function(){
                //随机数
            random=parseInt(Math.random()*arr.length)
            // console.log(arr[random])
            qs.innerHTML=arr[random]
            },35)
            //如果数组中只剩一个值,就不需要抽取了,让两个按钮禁用即可
            if(arr.length===1){
                start.disabled=true
                end.disabled=true
            }
        })
        // 2.关闭按钮模块
        const end=document.querySelector('.end')
        end.addEventListener('click',function(){
            //关闭定时器
            clearInterval(timerId)
            //结束之后 可以删除掉当前抽取的那个数组元素
            arr.splice(random,1)
            console.log(arr)
        })

    </script>
</body>

</html>

事件监听版本

  • DOML0

事件源.on事件=function(){}

    const btn=document.querySelector('button')
    btn.onclick=function(){
      alert(11)
    }
  • DOML2

事件源.addEventListener(事件,事件处理函数)

  • 区别:

on方式会被覆盖,addEventListener方式可绑定多次,拥有事件更多特性,推荐使用

事件类型

鼠标事件

鼠标触发

  • click 鼠标点击
  • mouseenter 鼠标经过
  • mouseleave 鼠标离开

焦点事件

表单获得光标

  • focus 获得焦点
  • blur 失去焦点
    const input=document.querySelector('input')
    input.addEventListener('focus',function(){
      console.log('有焦点触发')
    })
    input.addEventListener('blur',function(){
      console.log('失去焦点触发')
    })

键盘事件

键盘触发

  • Keydown 键盘按下触发
  • Keyup 键盘抬起触发
    // 1. 键盘事件
    const input=document.querySelector('input')
    input.addEventListener('keydown',function(){
      console.log('键盘按下了')
    })
    input.addEventListener('keyup',function(){
      console.log('键盘弹起了')
    })
    // 2.用户输入文本事件 input
    input.addEventListener('input',function(){
      console.log(input.value)//获取输入内容
    })

文本事件

表单输入触发

input 用户输入事件

轮播图点击切换

需求:当点击左右的按钮,可以切换轮播图

分析:

  1. 右侧按钮点击,变量++,如果大于等于8,则复原0
  2. 左侧按钮点击,变量--,如果小于0,则复原最后一张
  3. 鼠标经过暂停计时器
  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>
    * {
      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>
    // 1. 初始数据
    const Data = [
      { 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')
    // 1.右按钮业务
    // 1.1 获取右侧按钮
    const next=document.querySelector('.next')
    let i=0
    // 1.2 注册点击事件
    next.addEventListener('click',function(){
      // console.log(11)
      i++
      // 1.6 判断条件 如果大于8 就复原为0
      i=i>=Data.length?0:i
      // 1.3得到对应的对象
      // console.log(Data[i])
      img.src=Data[i].url
      p.innerHTML=Data[i].title
      footer.style.backgroundColor=Data[i].color
      // 1.5 更换小圆点 先移除原来的类名 当前li再添加 这个类名
      document.querySelector('.slider-indicator .active').classList.remove('active')
      document.querySelector(`.slider-indicator li:nth-child(${i+1})`).classList.add('active')
    })
  // 1.右按钮业务
    // 1.1 获取左侧按钮
    const prev=document.querySelector('.prev')
    prev.addEventListener('click',function(){
      // console.log(11)
      i--
      // 1.6 判断条件 如果小于0 则跑到最后一张图片索引号是7
      i=i<0?Data.length-1:i
      // 1.3得到对应的对象
      // console.log(Data[i])
      img.src=Data[i].url
      p.innerHTML=Data[i].title
      footer.style.backgroundColor=Data[i].color
      // 1.5 更换小圆点 先移除原来的类名 当前li再添加 这个类名
      document.querySelector('.slider-indicator .active').classList.remove('active')
      document.querySelector(`.slider-indicator li:nth-child(${i+1})`).classList.add('active')
    })
    //3.自动播放模块
    let timerId=setInterval(function(){
      //利用js自动调用点击事件 click必须加()
      next.click()
    },1000)
    // 4.鼠标经过大盒子,停止定时器
    const slider=document.querySelector('.slider')
    //注册事件
    slider.addEventListener('mouseenter',function(){
      //停止定时器
      clearInterval(timerId)
    })
    // 5.鼠标离开大盒子,开启定时器
    slider.addEventListener('mouseleave',function(){
      //开启定时器
      timerId=setInterval(function(){
      //利用js自动调用点击事件 click必须加()
      next.click()
    },1000)
    })
  </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>轮播图点击切换</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>
    // 1. 初始数据
    const Data = [
      { 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')
    // 1.右按钮业务
    // 1.1 获取右侧按钮
    const next=document.querySelector('.next')
    let i=0
    // 1.2 注册点击事件
    next.addEventListener('click',function(){
      // console.log(11)
      i++
      // 1.6 判断条件 如果大于8 就复原为0
      i=i>=Data.length?0:i
      toggle()
    })
  // 1.右按钮业务
    // 1.1 获取左侧按钮
    const prev=document.querySelector('.prev')
    prev.addEventListener('click',function(){
      // console.log(11)
      i--
      // 1.6 判断条件 如果小于0 则跑到最后一张图片索引号是7
      i=i<0?Data.length-1:i
      toggle()
    })
    //声明一个渲染函数作为复用
    function toggle(){
       // 1.3得到对应的对象
      // console.log(Data[i])
      img.src=Data[i].url
      p.innerHTML=Data[i].title
      footer.style.backgroundColor=Data[i].color
      // 1.5 更换小圆点 先移除原来的类名 当前li再添加 这个类名
      document.querySelector('.slider-indicator .active').classList.remove('active')
      document.querySelector(`.slider-indicator li:nth-child(${i+1})`).classList.add('active')
    }
    //3.自动播放模块
    let timerId=setInterval(function(){
      //利用js自动调用点击事件 click必须加()
      next.click()
    },1000)
    // 4.鼠标经过大盒子,停止定时器
    const slider=document.querySelector('.slider')
    //注册事件
    slider.addEventListener('mouseenter',function(){
      //停止定时器
      clearInterval(timerId)
    })
    // 5.鼠标离开大盒子,开启定时器
    slider.addEventListener('mouseleave',function(){
      //开启定时器
      timerId=setInterval(function(){
      //利用js自动调用点击事件 click必须加()
      next.click()
    },1000)
    })
  </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>
        * {
            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 {
            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 input=document.querySelector('[type=search]')
        const ul=document.querySelector('.result-list')
        console.log(input)
        // 2.监听事件 获得焦点
        input.addEventListener('focus',function(){
                ul.style.display='block'
                input.classList.add('search')
            })
        //3.监听事件 失去焦点
        input.addEventListener('blur',function(){
                ul.style.display='none'
                input.classList.remove('search')
            })

    </script>
</body>

</html>

评论字数统计

需求:用户输入文字,可以计算用户输入的字数

分析:

  1. 判断用输入事件 input
  2. 不断取得文本框里的字符长度,文本域.value.length
  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>评论回车发布</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;
    }

    .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')

  // 1. 当文本域获得了焦点,就让total显示出来
tx.addEventListener('focus',function(){
  total.style.opacity=1
})
  //2. 当文本域失去了焦点,就让total隐藏
  tx.addEventListener('blur',function(){
  total.style.opacity=0
})
//3.检测用户输入
tx.addEventListener('input',function(){
  //console.log(tx.value.length)  得到输入的长度
  total.innerHTML=`${tx.value.length}/200字`
})
</script>
</body>

</html>

事件对象

获取事件对象

  • 事件对象是什么

也是个对象,这个对象里有事件触发时的相关信息

例如:鼠标点击事件中,事件对象就存了鼠标点在哪个位置等信息

  • 使用场景

可以判断用户按下哪个键,比如按下回车键可以发布新闻

可以判断鼠标点击了哪个元素,从而做出相应的操作

  • 语法:

在事件绑定的回调函数的第一个参数就是事件对象

一般命名为event,ev,e

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

事件对象常用属性

  • type:获取当前的事件类型
  • clientX/clientY:获取光标对于浏览器可见窗口左上角的位置
  • offsetX/offsetY:获取光标相对于DOM元素左上角的位置
  • key:用户按下的键盘键的值,不提倡使用keyCode

trim方法

作用:去除字符串两边的空格,中间的空格保留

    const str='        pink'
    console.log(str.trim())

评论回车发布

需求:按下回车键,可以发布信息

  1. 用到按下键盘事件keydown或者keyup都可以
  2. 如果用户按下的是回车键盘,则发布信息
  3. 让留言信息模块显示把拿到的数据渲染到对应标签内部

小tip:用户按下回车之后,input文本框里的文字会清除,且若用户输出的全为空格,则不输出,输出结果去除用户内容左右两端的空格

<!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>
    .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/bg01.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;
    }

    .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 item=document.querySelector('.item')
  const text=document.querySelector('.text')
  // 1. 当文本域获得了焦点,就让total显示出来
tx.addEventListener('focus',function(){
  total.style.opacity=1
})
  //2. 当文本域失去了焦点,就让total隐藏
  tx.addEventListener('blur',function(){
  total.style.opacity=0
})
//3.检测用户输入
tx.addEventListener('input',function(){
  //console.log(tx.value.length)  得到输入的长度
  total.innerHTML=`${tx.value.length}/200字`
})
// 4.按下回车键发布评论
tx.addEventListener('keyup',function(e){
  //只有按下的是回车键,才会触发
  if(e.key==='Enter'){
    // console.log(11) 测试
    if(tx.value.trim()!==''){//输出内容不全为空格
      item.style.display='block'
    // console.log(tx.value)
    text.innerHTML=tx.value
    }
    //等我们按下回车,结束,清空input里的值
    tx.value=''
    //按下回车之后,就要把字符统计复原
    total.innerHTML='0/200字'
  }
})
</script>
</body>

</html>

环境对象

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

作用:弄清楚this的指向,可以让我们的代码更简洁

  • 函数的调用方式不同,this指向的对象也不同
  • 谁调用,this就是谁(粗略规则)
  • 直接调用函数,其实就是相当于是window函数,所以this指代window
    //每个函数里面都有this 环境对象 普通函数里面this指向的是window
    // function fn(){
    //   console.log(this)
    // }
    // window.fn()
    const btn=document.querySelector('button')
    btn.addEventListener('click',function(){
      // console.log(this)//this指向函数的调用者 在这里即btn
      //btn.style.color='red'
      this.style.color='red'
    })

回调函数

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

简单理解,当一个函数作为参数传递给另外一个函数的时候,这个函数就是回调函数

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:;" data-id="0">精选</a></li>
        <li><a href="javascript:;" data-id="1">美食</a></li>
        <li><a href="javascript:;" data-id="2">百货</a></li>
        <li><a href="javascript:;" data-id="3">个护</a></li>
        <li><a href="javascript:;" data-id="4">预告</a></li>
      </ul>
    </div>
    <div class="tab-content">
      <div class="item active"><img src="./images1/tab00.png" alt="" /></div>
      <div class="item"><img src="./images1/tab01.png" alt="" /></div>
      <div class="item"><img src="./images1/tab02.png" alt="" /></div>
      <div class="item"><img src="./images1/tab03.png" alt="" /></div>
      <div class="item"><img src="./images1/tab04.png" alt="" /></div>
    </div>
  </div>
  <script>
    // 1.a 模块制作 要给5个链接绑定鼠标经过事件
    // 1.1获取a元素
    const as=document.querySelectorAll('.tab-nav a')
    console.log(as)
    for(let i=0;i<as.length;i++){
      // console.log(as[i])
      as[i].addEventListener('mouseenter',function(){
        // console.log('鼠标经过')
        //排他思想
        // 先去除类名active
        document.querySelector('.tab-nav .active').classList.remove('active')
        // 添加类名active
        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')
      })
    }
    //采取事件委托的形式 tab栏切换
    //1. 获取ul 父元素 因为ul只有一个
    const ul=document.querySelector('.tab-nav ul')
    const items=document.querySelectorAll('.tab-content .item')//item是数组
    //2.添加事件
    ul.addEventListener('click',function(e){
      //console.log('e.target') //e.target是我们点击的对象
      // 我们只有点击了a才会进行添加类和删除类操作
      // console.log(e.target.tagName)
      if(e.target.tagName==='A'){
        // console.log('我选的是a')
        // 排他思想 先移除原来的active 当前元素添加 active
        document.querySelector('.tab-nav .active').classList.remove('active')
        //当前元素添加active
        // this指向ul 不能指代li
        e.target.classList.add('active')
        //下面大盒子模块
        // console.log(e.target.dataset.id)
        const i=+e.target.dataset.id//注意接收的值为数值型,接收回来的是字符型
        //排他思想 先移除active
        document.querySelector('.tab-content .active').classList.remove('active')
        //对应的大盒子 添加 active
        // document.querySelector(`.tab-content .item:nth-child(${i+1})`).classList.add('active')
        items[i].classList.add('active')
        // console.log(document.querySelector(`.tab-content .item:nth-child(${i+1})`))
      }
    })
  </script>
</body>

</html>

 全选文本框案例1

需求:用户点击全选,则下面复选框全部选择,取消全选则全部取消

分析:

  1. 全选复选框点击,可以得到当前按钮的checked
  2. 把下面所有的小复选框状态checked,改为和全选复选框一致

小tip:

.类名:checked{},可直接设置多选框被选中之后的样式·

<!DOCTYPE html>

<html>

<head lang="en">
  <meta charset="UTF-8">
  <title></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;
    }
  </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 checkAll=document.querySelector('#checkAll')
    // 2.获取所有的小复选框
    const cks=document.querySelectorAll('.ck')
    // 3.点击大复选框 注册事件
    checkAll.addEventListener('click',function(){
      //得到当前大复选框的选中状态
      //console.log(checkAll.checked)//得到是true或者是false
      //4. 遍历所有的小复选框 让复选框所有的checked=大复选框的checked
      for(let i=0;i<cks.length;i++){
        cks[i].checked=checkAll.checked;//chexkedAll也可写成this
      }
    })
  </script>
</body>

</html>

全选反选案例2

需求:用户点击全选,则下面复选框全部选择,取消全选则全部取消,文字对应变化

分析:

  1. 遍历下面所有的checked,添加点击事件
  2. 检查小复选框选中的个数,是不是等于小复选框总的个数
  3. 把结果给全选按钮
  4. 利用css复选框选择器 input:checked
    // 5.小复选框控制大复选框
    for(let i=0;i<cks.length;i++){
      // 5.1给所有的小复选框添加点击事件
      // 判断选中的小复选框个数 是不是等于 总的小复选框个数
      // 一定要写到点击里面 因为每次都要获得最新的个数
      cks[i].addEventListener('click',function(){
        // console.log(document.querySelectorAll('.ck:checked').length===cks.length)
        checkAll.checked=document.querySelectorAll('.ck:checked').length===cks.length
      })
    }

事件流

  • 事件流指的是事件完整执行过程中的流动路径
  • 说明:假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段
  • 简单来说:捕获阶段是从父到子,冒泡阶段是从子到父
  • 实际工作都是使用事件冒泡为主

事件捕获

  • 事件捕获概念:从DOM的根元素开始执行对应的事件(从外到里)
  • 事件捕获需要写对应的代码才能看到效果
  • 代码:
DOM.addEventListener(事件类型,事件处理函数,是否使用捕获机制)
  • 说明:addEventListener第三个参数传入true代表是捕获阶段触发(很少使用)
  • 若传入false代表冒泡阶段触发,默认就是false
  • 若是用L0事件监听,则只有冒泡阶段,没有捕获

事件冒泡

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

  • 简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的同名事件
  • 事件冒泡是默认存在的
  • L2事件监听第三个参数是flase,或者默认都是冒泡
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .father{
      width: 500px;
      height: 500px;
      background-color: pink;
    }
    .son {
      width: 200px;
      height: 200px;
      background-color:purple;
    }
  </style>
</head>
<body>
  <div class="father">
    <div class="son"></div>
  </div>
  <script>
    const fa=document.querySelector('.father')
    const son=document.querySelector('.son')
    document.addEventListener('click',function(){
      alert('我是爷爷')
    })
    fa.addEventListener('click',function(){
      alert('我是爸爸')
    })
    son.addEventListener('click',function(){
      alert('我是儿子')
    })
    // DOM.addEventListener(事件类型,事件处理函数,是否使用捕获机制)
  </script>
</body>
</html>

上面代码在鼠标点击儿子之后,会先弹出”我是儿子“,点击确定之后,会再次自动弹出”我是爸爸“,之后是”我是爷爷“ 

阻止冒泡

问题:因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素

需求:若想把事件就限制在当前元素内,就需要阻止事件冒泡

前提:阻止事件冒泡需要拿到事件对象

语法

事件对象.stoPropagation()
    const fa=document.querySelector('.father')
    const son=document.querySelector('.son')
    document.addEventListener('click',function(){
      alert('我是爷爷')
    })
    fa.addEventListener('click',function(){
      alert('我是爸爸')
    })
    son.addEventListener('click',function(e){
      alert('我是儿子')
      e.stopPropagation()
    })

 给儿子添上阻止冒泡,父亲和爷爷就不会弹出来

注意: 此方法可以阻断时间流动传播,不光在冒泡阶段有效,捕获阶段也有效

解绑事件

on事件方式,直接使用null覆盖就可以实现事件的解绑

语法:L0事件移除解绑

    const btn=document.querySelector('.btn')
    //绑定事件
    btn.onclick=function(){
      alert('点击了')
    }
    // L0 事件移除解绑
    // btn.onclick=null

addEventListener 方式,必须使用:

removeEventListener(事件类型,事件处理函数,[获取捕获或者冒泡阶段])

例如:

    function fn(){
      alert('点击了')
    }
    btn.addEventListener('click',fn)
    //L2 事件移除解绑
    btn.removeEventListener('click',fn)

注意:匿名函数不可被解绑

鼠标经过事件:

  • mouseover和mouseout会有冒泡效果
  • mouseenter和mouseleave 没有冒泡效果(推荐)
    const dad=document.querySelector('.dad')
    const baby=document.querySelector('.baby')
    dad.addEventListener('mouseover',function(){
      console.log('爸爸经过')
    })
    dad.addEventListener('mouseout',function(){
      console.log('爸爸离开')
    })
    baby.addEventListener('mouseover',function(){
      console.log('儿子经过')
    })
    baby.addEventListener('mouseout',function(){
      console.log('儿子离开')
    })

两种注册事件的区别

传统on注册(L0)

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

事件监听注册(L2)

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

事件委托

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

  •         优点:减少注册次数,可以提高程序性能
  •         原理:事件委托其实是利用事件冒泡的特点。

                给父元素注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <ul>
    <li>第1个孩子</li>
    <li>第2个孩子</li>
    <li>第3个孩子</li>
    <li>第4个孩子</li>
    <li>第5个孩子</li>
    <p>我不需要变色</p>
  </ul>
  <script>
    //点击每个小li,当前li 文字变为红色
    //按照事件委托的方式 委托给父级 事件写到父级身上
    //1.获得父元素
    const ul=document.querySelector('ul')
    ul.addEventListener('click',function(e){
      // console.log(e)//e是点击的事件对象
      // e.target.style.color='red'//e.rarget指的是点击的具体元素标签
      // 需求:只要点击li才会有效果
      if(e.target.tagName==='LI'){
        e.target.style.color='red'//e.rarget指的是点击的具体元素标签
      }
    })
  </script>
</body>
</html>

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:;" data-id="0">精选</a></li>
        <li><a href="javascript:;" data-id="1">美食</a></li>
        <li><a href="javascript:;" data-id="2">百货</a></li>
        <li><a href="javascript:;" data-id="3">个护</a></li>
        <li><a href="javascript:;" data-id="4">预告</a></li>
      </ul>
    </div>
    <div class="tab-content">
      <div class="item active"><img src="./images1/tab00.png" alt="" /></div>
      <div class="item"><img src="./images1/tab01.png" alt="" /></div>
      <div class="item"><img src="./images1/tab02.png" alt="" /></div>
      <div class="item"><img src="./images1/tab03.png" alt="" /></div>
      <div class="item"><img src="./images1/tab04.png" alt="" /></div>
    </div>
  </div>
  <script>
    // // 1.a 模块制作 要给5个链接绑定鼠标经过事件
    // // 1.1获取a元素
    // const as=document.querySelectorAll('.tab-nav a')
    // console.log(as)
    // for(let i=0;i<as.length;i++){
    //   // console.log(as[i])
    //   as[i].addEventListener('mouseenter',function(){
    //     // console.log('鼠标经过')
    //     //排他思想
    //     // 先去除类名active
    //     document.querySelector('.tab-nav .active').classList.remove('active')
    //     // 添加类名active
    //     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')
    //   })
    // }
    /
    //采取事件委托的形式 tab栏切换
    //1. 获取ul 父元素 因为ul只有一个
    const ul=document.querySelector('.tab-nav ul')
    const items=document.querySelectorAll('.tab-content .item')
    //2.添加事件
    ul.addEventListener('click',function(e){
      //console.log('e.target') //e.target是我们点击的对象
      // 我们只有点击了a才会进行添加类和删除类操作
      // console.log(e.target.tagName)
      if(e.target.tagName==='A'){
        // console.log('我选的是a')
        // 排他思想 先移除原来的active 当前元素添加 active
        document.querySelector('.tab-nav .active').classList.remove('active')
        //当前元素添加active
        // this指向ul 不能指代li
        e.target.classList.add('active')
        //下面大盒子模块
        // console.log(e.target.dataset.id)
        const i=+e.target.dataset.id//注意接收的值为数值型,接收回来的是字符型
        //排他思想 先移除active
        document.querySelector('.tab-content .active').classList.remove('active')
        //对应的大盒子 添加 active
        // document.querySelector(`.tab-content .item:nth-child(${i+1})`).classList.add('active')
        items[i].classList.add('active')
        // console.log(document.querySelector(`.tab-content .item:nth-child(${i+1})`))
      }
    })

  </script>
</body>

</html>

小tip

自定义属性:

  <div data-id="0"></div>
  <script>
    const div =document.querySelector('div')
    console.log(div.dataset.id)//0
  </script>

阻止默认行为

在某些情况下需要阻止默认行为的发生,比如阻止链接的跳转,表单域跳转

语法

  <form action="http://www.itcast.cn">
  <input type="submit" value="免费注册">
  </form>
  <a href="http://www.baidu.com">百度一下</a>
  <script>
    const form=document.querySelector('form')
    form.addEventListener('submit',function(e){
      //阻止默认行为 提交
      e.preventDefault()
    })
    const a=document.querySelector('a')
    a.addEventListener('click',function(e){
      e.preventDefault()
    })
  </script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值