首页 🚓JavaScript

webapi-day05

事件流:

1-事件冒泡和事件捕获

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <style>
      .father {
        width: 400px;
        height: 400px;
        margin: 100px auto;
        background-color: #f99;
      }

      .son {
        width: 300px;
        height: 300px;
        background-color: skyblue;
      }

      .sun {
        width: 200px;
        height: 200px;
        background-color: lightgreen;
      }
    </style>
  </head>

  <body>
    <div class="father">
      <div class="son">
        <div class="sun"></div>
      </div>
    </div>

    <script>
      // 事件冒泡: 任何一个元素的事件触发了, 该事件就在元素所有祖先元素上依次来触发该事件(从里到外.)

      let father = document.querySelector('.father');
      let son = document.querySelector('.son');
      let sun = document.querySelector('.sun');

      let arr = [document, document.body, father, son, sun];

      // 遍历数组,来给数组里面每一个元素注册点击事件
      // 事件触发了,当前触发事件的元素,事件源
      for (let i = 0; i < arr.length; i++) {
        arr[i].addEventListener(
          'click',
          function () {
            console.log(this);
          },
          ture
        );
      }
    </script>
  </body>
</html>

2-事件的三个阶段

  • 任何一个事件的触发, 都要经历三个阶段:
  • 1. 捕获阶段
  • 2. 目标阶段
  • 3. 冒泡阶段

元素注册事件只会触发一次,要么是在捕获阶段要么在冒泡阶段触发 addEventListener第三个参数useCapture的值

true 捕获阶段触发 false冒泡阶段触发 on 注册的方式 冒泡阶段触发

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

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        .father {
            width: 400px;
            height: 400px;
            margin: 100px auto;
            background-color: #f99;
        }

        .son {
            width: 300px;
            height: 300px;
            background-color: skyblue;
        }

        .sun {
            width: 200px;
            height: 200px;
            background-color: lightgreen;
        }
    </style>
</head>

<body>
    <div class="father">
        <div class="son">
            <div class="sun"></div>
        </div>
    </div>

    <script>
        // 事件的三个阶段 (事件流)
        // 任何一个事件的触发, 都要经历三个阶段: 
        //  1. 捕获阶段
        //  2. 目标阶段
        //  3. 冒泡阶段

        // 元素注册的事件只会触发一次,要么是在捕获阶段要么在冒泡阶段触发
        //  addEventListener第三个参数useCapture的值
        //          true 捕获阶段触发
        //          false 冒泡阶段触发
        //  on 注册的方式  冒泡阶段触发

        let father = document.querySelector(".father");
        let son = document.querySelector(".son");
        let sun = document.querySelector(".sun");

        document.addEventListener("click", function () {
            console.log(this)
        }, true)

        document.body.addEventListener("click", function () {
            console.log(this)
        }, false)

        father.addEventListener("click", function () {
            console.log(this)
        }, true)

        son.addEventListener("click", function () {
            console.log(this)
        }, false)

        sun.addEventListener("click", function () {
            console.log(this)
        }, true)
    </script>
</body>

</html>

3-登录框-演示阻止事件冒泡

<!DOCTYPE html>
<html>

<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    body {
      background: rgba(64, 64, 64, .7);
    }

    .login-header {
      width: 100%;
      text-align: center;
      height: 30px;
      font-size: 24px;
      line-height: 30px;

    }

    .login-header a {
      color: #fff;
    }

    ul,
    li,
    ol,
    dl,
    dt,
    dd,
    div,
    p,
    span,
    h1,
    h2,
    h3,
    h4,
    h5,
    h6,
    a {
      padding: 0px;
      margin: 0px;
    }

    .login {
      width: 512px;
      height: 280px;
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      border: #ebebeb solid 1px;
      background: #ffffff;
      box-shadow: 0px 0px 20px #ddd;
      z-index: 9999;
      display: block;
    }

    .login-title {
      width: 100%;
      margin: 10px 0px 0px 0px;
      text-align: center;
      line-height: 40px;
      height: 40px;
      font-size: 18px;
      position: relative;
      /* cursor: move; */
      user-select: none;
      /*  火狐  */
      -moz-user-select: none;
      /*webkit浏览器*/
      -webkit-user-select: none;
      /*IE10*/
      -ms-user-select: none;
      /*早期浏览器*/
      -khtml-user-select: none;
    }

    .login-input-content {
      margin-top: 20px;
    }

    .login-button {
      width: 50%;
      margin: 30px auto 0px auto;
      line-height: 40px;
      font-size: 14px;
      border: #ebebeb 1px solid;
      text-align: center;
    }

    .login-bg {
      width: 100%;
      height: 100%;
      position: fixed;
      top: 0px;
      left: 0px;
      background: #000000;
      filter: alpha(opacity=30);
      opacity: 0.3;
      display: none;
    }

    a {
      text-decoration: none;
      color: #000000;
    }

    .login-button a {
      display: block;
    }

    .login-input input.list-input {
      float: left;
      line-height: 35px;
      height: 35px;
      width: 350px;
      border: #ebebeb 1px solid;
      text-indent: 5px;
    }

    .login-input {
      overflow: hidden;
      margin: 0px 0px 20px 0px;
    }

    .login-input label {
      float: left;
      width: 90px;
      padding-right: 10px;
      text-align: right;
      line-height: 35px;
      height: 35px;
      font-size: 14px;
    }

    .login-title span {
      position: absolute;
      font-size: 12px;
      right: -20px;
      top: -30px;
      background: #ffffff;
      border: #ebebeb solid 1px;
      width: 40px;
      height: 40px;
      border-radius: 20px;
      z-index: 99;
      cursor: pointer;
    }
  </style>
</head>

<body>
  <div class="login-header"><a id="link" href="javascript:void(0);">点击,弹出登录框</a></div>
  <div id="login" class="login">
    <div id="title" class="login-title">登录会员
      <span id="closeBtn">关闭</span>
    </div>
    <div class="login-input-content">
      <div class="login-input">
        <label>用户名:</label>
        <input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input">
      </div>
      <div class="login-input">
        <label>登录密码:</label>
        <input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="list-input">
      </div>
    </div>
    <div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登录会员</a></div>
  </div>

  <script>
    // 演示事件冒泡带来的问题
    //  阻止事件冒泡 通过事件对象e的 stopPropagation 方法

    let link = document.querySelector("#link");
    let login = document.querySelector("#login");
    let closeBtn = document.querySelector("#closeBtn");

    // 点击页面document隐藏login登录框
    document.onclick = function () {
      login.style.display = 'none'
      console.log('document ---- none')
    }

    // 点击link显示login登录框
    link.onclick = function (e) {
      login.style.display = 'block'
      e.stopPropagation()
      console.log('link ---- block')
    }

    // 点击closeBtn隐藏login登录框
    closeBtn.onclick = function () {
      login.style.display = 'none'
    }

    // 当点击login的时候,来阻止事件冒泡
    login.onclick = function (e) {
      e.stopPropagation()
    }
  </script>
</body>

</html>

4-阻止浏览器的默认行为

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

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
    <form action="http://baidu.com">
        <input type="text" name="username">
        <button type="submit">提交</button>
    </form>

    <a href="http://www.baidu.com">百度一下</a>

    <script>
        // 阻止浏览器的默认行为
        //  1. a链接默认跳转行为
        //  2. 回车默认换行
        //  3. 表单提交功能
        //  ...

        let link = document.querySelector("a");

        // 阻止a链接默认跳转行为
        //  1. return false
        //  2. 事件对象e有preventDefault() 方法  阻止默认行为
        //  3. href = "javascript:void(0);"

        //  前2种方式可以用于阻止其他的默认行为
        //  最后一种适用于阻止a链接跳转的

        /* link.onclick = function (e) {
            e.preventDefault()

            alert(1)
        } */

        // return false 这种写法有缺点,不适用addEventListener注册的事件
        link.addEventListener('click', function (e) {
            alert(2)
            // return false; // 无法阻止
            e.preventDefault()
        })

        // 事件对象有哪些属性和方法
        //  1. e.pageX   e.pageY
        //  2. e.key 
        //  3. e.stopPropagation()  阻止事件冒泡
        //  4. e.preventDefault()   阻止浏览器默认行为
    </script>
</body>

</html>

5-为啥要事件委托

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

<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    ul {
      background-color: #f99;
      padding: 20px;
      width: 800px;
    }

    li {
      padding: 10px;
      background-color: greenyellow;
      margin: 20px;
    }
  </style>
</head>

<body>
  <button id="create">新建li</button>
  <ul>
    <li>这是第1个li</li>
    <li>这是第2个li</li>
    <li>这是第3个li</li>
    <li>这是第4个li</li>
    <li>这是第5个li</li>
    <li>这是第6个li</li>
    <li>这是第7个li</li>
    <li>这是第8个li</li>
    <li>这是第9个li</li>
    <li>这是第10个li</li>
  </ul>
  <script>
    // 需求:点击li元素弹出哈哈

    // 常规做法:找到所有的li,给所有的li注册click
    let lis = document.querySelectorAll("li");
    let create = document.querySelector("#create");
    let ul = document.querySelector('ul')

    /* for (let i = 0; i < lis.length; i++) {
      lis[i].onclick = function () {
        alert("哈哈");
      }
    } */

    // 以上实现的方式有缺点
    //  1. 给每一个元素都注册上click事件,做的事情都一样,会有内存浪费问题(绑定注册事件多次)
    //  2. 新建的元素没有事件的

    // 点击按钮新建li添加到ul中
    create.onclick = function () {
      let newLi = document.createElement("li"); // <li></li>
      newLi.innerText = '新建的li'      // <li>新建的li</li>
      ul.appendChild(newLi);
    }

    // 事件委托做法(使用事件委托可以来解决常规写法的问题)
    //  做法: 把事件注册给父元素(祖先元素)
    //  原理: 事件冒泡
    document.onclick = function () {
      alert("哈哈");
    }
  </script>

</body>

</html>

6-事件委托-this和e.target区别

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

<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    #box {
      width: 100px;
      height: 100px;
      background-color: #f99;
    }

    ul {
      background-color: #f99;
      padding: 20px;
      width: 800px;
    }

    li {
      padding: 10px;
      background-color: greenyellow;
      margin: 20px;
    }
  </style>
</head>

<body>
  <ul>
    <li>这是第1个li</li>
    <li>这是第2个li</li>
    <li>这是第3个li</li>
    <li>这是第4个li</li>
    <li>这是第5个li</li>
    <li>这是第6个li</li>
    <li>这是第7个li</li>
    <li>这是第8个li</li>
    <li>这是第9个li</li>
    <li>这是第10个li</li>
  </ul>
  <script>
    // 需求:区分this和e.target区别

    // 事件委托做法
    // 以下写法,不仅仅是点击li,点击其他元素都会弹框
    //  优化:只能点击li,才能弹框
    //  难点:如何得知点击的具体元素是谁???
    document.onclick = function (e) {
      // console.log(this) // 事件源 document
      // console.dir(e.target) // 得知点击的具体是哪个元素

      if (e.target.nodeName === 'LI') {
        // if成立,点击的是li元素才能让if执行
        alert('哈哈')
      }
    }
  </script>
</body>

</html>

7-微博发布-事件委托

<!DOCTYPE html>
<html>

<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    ul {
      list-style: none;
    }

    .box {
      width: 600px;
      margin: 100px auto;
      border: 1px solid #000;
      padding: 20px;
    }

    textarea {
      width: 450px;
      height: 160px;
      outline: none;
      resize: none;
    }

    ul {
      width: 450px;
      padding-left: 80px;
    }

    ul li {
      line-height: 25px;
      border-bottom: 1px dashed #cccccc;
    }

    input {
      float: right;
    }
  </style>
</head>

<body>
  <div class="box" id="weibo">
    <span>微博发布</span>
    <textarea name="" id="txt" cols="30" rows="10"></textarea>
    <button id="btn">发布</button>
    <ul id="ul">
      <!-- <li>哈哈 <button>删除</button></li> -->
    </ul>
  </div>
  <script>

    // 事件委托案例
    //  把删除案例的点击事件 换成事件委托写法


    let txt = document.querySelector('#txt')
    let btn = document.querySelector('#btn')
    let ul = document.querySelector('#ul')

    btn.onclick = function () {
      let content = txt.value.trim()    // '     '.trim() ==> ''
      // console.log(content, content.length)

      // 当获取到文本域的内容之后,先判断是否有内容,有就可以创建li,li添加到ul中
      // 没有内容,就不执行后续代码
      if (content.length === 0) {
        // if成立,没有内容 后续代码不执行 return
        return alert('请输入内容')
      }

      // 4. 
      let newLi = document.createElement('li')
      newLi.innerText = content
      // console.log(newLi)

      // 5. 
      // 需要把newLi添加到第一个的前面
      // ul.firstElementChild 第一个子元素
      ul.insertBefore(newLi, ul.firstElementChild)

      // 清空文本域的内容
      txt.value = ''

      // 6.   delete 删除
      let delBtn = document.createElement('button')

      // 7.  创建li 叫newLi
      newLi.appendChild(delBtn)

      // 8. 
      delBtn.innerText = '删除'
      // 右浮动
      delBtn.style.float = 'right'
      // 点击功能
      /* delBtn.onclick = function () {
        // console.log(this)
        // 删除当前的评论消息(li)

        // parent.removeChild(child) 方法
        //  child ==> newLi
        //  parent ==> ul

        ul.removeChild(newLi)
      } */
    }

    // 事件委托写法
    //  把事件委托注册给父元素(或者祖先元素)
    ul.onclick = function (e) {
      // console.log(e.target.nodeName)
      if (e.target.nodeName === 'BUTTON') {
        // console.log('点击了删除按钮')

        // 只能点击删除按钮 才可以删除
        // ul.removeChild(newLi)  // error newLi 无法获取到

        // 需要删除的li元素 ==> 当前点击的删除按钮的父元素
        // console.log(e.target)
        // console.log(e.target.parentNode)

        ul.removeChild(e.target.parentNode)
      }
    }

    txt.onkeyup = function (e) {
      if (e.key === 'Enter') {
        btn.onclick()
      }
    }
  </script>
</body>

</html>

BOM:

01-window 对象

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>

  <body>
    <script>
      // window 对象
      /*
        window对象是js里面的全局对象(表示可以在任何位置来使用window对象)
        1,document console.log(alert) 等属性和方法等于windows对象
        window对象非常常用,可以省略不写
        window.alert(‘哈哈哈)
        window.console.log(window.document)
        2,在全局中定义的函数也是属于window对象

        */
      function fn() {
        console.log('is fn');
      }
      fn();
      window.fn();
    </script>
  </body>
</html>

02-延时器

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>

  <body>
    <script>
      // 需求: 延时3秒后执行fn函数
      // 参数
      //  fn 延时执行的函数
      //  delay 延时的事件 单位是ms
      //  返回值:开启的延时器的id编号

      // 表示延时1秒5在执行函数

      // 延时器

      // setTimeout(() => {
      //   console.log('延时执行了?');
      // }, 1500);
      function fn() {
        console.log('fn 执行了');
      }

      fn(); //立即执行
      setTimeout(fn(), 3000);
    </script>
  </body>
</html>

03-清除延时器

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>

  <body>
    <button>开启延时器</button>
    <button>关闭延时器</button>

    <script>
      let btn1 = document.querySelectorAll('button')[0];
      let btn2 = document.querySelectorAll('button')[1];

      // 开启延时器
      let timerId;
      btn1.onclick = function () {
        console.log('丢了克雷');
        timerId = setTimeout(function () {
          console.log('BOOM SHAKELAKA');
        }, 3000);
      };

      // 清除延时器
      btn2.onclick = function () {
        console.log('拆雷' + timerId);
        clearTimeout(timerId);
      };
      // 延时器
      /* 
      开启:let timerId=setTimeout(延时器执行的函数,延时时间) 返回值,延时器的id
      关闭:claerTimeout (延时器的id  timeId)
      */
    </script>
  </body>
</html>

04-定时器

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>

  <body>
    <script>
      // 定时器:
      //  语法: setInterval(fn,interval)
      //  参数: fn函数 interval 间隔时间 单位也是 MS
      //  返回值: 返回开启的定时器的id编号
      let timerId = setInterval(function () {
        console.log('执行了?');
      }, 10);
      console.log(timerId);

      // 清除定时器  clearInterval(id)  id 定时器的id编号  来源于开启定时器的返回值
      // clearInterval(timerId)

      // 小结
      // 延时器:延时一段时间来执行函数
      //       开启: setTimeout()
      //       关闭: clearTimeout()

      // 定时器: 每间隔一段时间来执行函数(如果不清除定时器,会一直执行下去)
      //        开启: setInterval()
      //        关闭: clearInterval()
    </script>
  </body>
</html>

05-电子表

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title></title>
    <style>
      #box {
        width: 400px;
        height: 50px;
        background-color: #acffc2;
        border: 5px solid black;
        margin: 100px auto;
        font: bold 24px/50px 楷体;
        text-align: center;
        color: red;
      }
    </style>
  </head>

  <body>
    <div id="box"></div>
    <script>
      let box = document.querySelector('#box');
      // new Date().toLocaleString() // 得到本地化的时间格式

      /* // 页面一打开就会执行一次(box里面一开始就会有内容)
        box.innerText = new Date().toLocaleString()

        // 开启一个定时器,每间隔一秒来获取到最新的时间,写入到box中
        setInterval(function () {
            // 每间隔一秒执行的
            box.innerText = new Date().toLocaleString()
        }, 1000) */

      // 优化  使用函数来封装重复代码

      function changeTime() {
        box.innerText = new Date().toLocaleString();
      }
      changeTime();
      setInterval(changeTime, 1000);
    </script>
  </body>
</html>

06-短信注册案例

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
    <style>
      .btn {
        height: 38px;
        width: 200px;
      }

      .btn[disabled] {
        cursor: no-drop;
      }
    </style>
  </head>

  <body>
    <button class="btn" type="button">获取验证码</button>
    <script>
      let btn = document.querySelector('.btn');

      btn.onclick = function () {
        btn.disabled = true;
        let count = 5;
        let timerId = setInterval(function () {
          count--;
          btn.innerText = count + '秒后再发送';
          if (count === 0) {
            btn.disabled = false;
            btn.innerText = '获取验证码';
            clearInterval(timerId);
          }
        }, 1000);
      };
    </script>
  </body>
</html>

07-自动跳转效果

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>
    <a href="http://www.baidu.com">注册成功,3秒后跳转到首页, 点击可立即跳转</a>
    <script>
        let link = document.querySelector("a");

        // 倒计时,更改a的内容,一旦倒计时为0,进行页面的跳转(location.href = xxx)

        let count = 3

        // 开定时器
        let timerId = setInterval(function () {
            count--
            link.innerText = `注册成功,${count}秒后跳转到首页, 点击可立即跳转`


            if (count === 0) {
                // 建议写上
                clearInterval(timerId)

                // 跳转页面 (把link的href属性值获取,给赋值location.href)
                location.href = link.href
            }
        }, 1000)
    </script>
</body>

</html>

JD秒杀:

<!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>
    <link rel="stylesheet" href="./index.css" />
  </head>

  <body>
    <a class="seckill-countdown" href="javascript:void(0)">
      <div class="countdown-title">京东秒杀</div>
      <div>
        <div class="countdown-desc"><strong>00:00</strong>点场 距结束</div>
        <span class="timmer countdown-main">
          <span class="timmer__unit timmer__unit--hour">09</span>
          <span class="timmer__unit timmer__unit--minute">47</span>
          <span class="timmer__unit timmer__unit--second">09</span>
        </span>
      </div>
    </a>

    <script>
      // 获取对象
      let hour = document.querySelector('.timmer__unit--hour');
      let minute = document.querySelector('.timmer__unit--minute');
      let second = document.querySelector('.timmer__unit--second');
      let inputTime = new Date('2021-9-17 20:10:00'); //倒计时的结束时间,自己设置时间

      //2、倒计时-时分秒函数

      let timerId = setInterval(function () {
        let nowTime = new Date(); //获取当前时间
        let times = (inputTime - nowTime) / 1000; // 倒计时,时间减去当前时间
        if (nowTime >= inputTime) {
          clearInterval(timerId);
          hour.innerText = '00';
          minute.innerText = '00';
          second.innerText = '00';
          return;
        }
        let h = parseInt((times / 60 / 60) % 24); //获取小时数
        h = h < 10 ? '0' + h : h; //判断数值小于10的情况 如 0-9改为 00-09
        hour.innerHTML = h; //更改div里面的内容 把h给获取元素hour的内容
        let m = parseInt((times / 60) % 60); //获取分钟
        m = m < 10 ? '0' + m : m;
        minute.innerHTML = m; //获取秒
        let s = parseInt(times % 60);
        s = s < 10 ? '0' + s : s;
        second.innerHTML = s; //获取毫秒
      }, 1000);
    </script>
  </body>
</html>

GIF




文章评论

目录