DOM相关

DOM01

DOM: Document Object Model

  • Document: 文档, 就是HTML代码

  • Object: 浏览器实际运行的不是HTML

    • HTML是文本 会被隐式转化成 JS的 对象类型, 然后运行到浏览器上

DOM: 才是浏览器中显示的内容的本体, 学习DOM之后可以灵活操作所有浏览器的技能

HTML本质: 是一套语法糖 写法

可以让程序员方便快捷的创建 DOM元素, 易读

不过: HTML 能够提供的操作特别有限, 无法适应实际开发的需求场景

HTML只能在页面上显示静态 的内容, 例如 图片/文字

DOM树

HTML 在转换成 DOM 对象的过程中, 称为 DOM 树结构

<!DOCTYPE html>
<html lang="en">
​
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>DOM</title>
</head>
​
<body>
  <div id="box">
    <button>家乐</button>
    <button>凯凯</button>
    <button>铭铭</button>
  </div>
​
  <script>
    // HTML代码本质是一套语法糖: 用于快速创建DOM元素
    // 实际运行后, 浏览器的底层会把HTML转换成 JS的元素, 存储在 window.document
    console.log(window)
    // log: 打印出来的是美化后的样子
    console.log(document)
    // dir: 直接输出对象本身
    console.dir(document);
  </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>DOM操作初体验</title>
​
  <style>
    /* DOM阶段 CSS 很重要: 到 xin88.top 有css参考, 周末去看 */
    #box {
      background-color: #1373c5;
      padding: 30px;
      border-radius: 10px;
      font-size: 30px;
      /* 粗体 */
      font-weight: bold;
      /* 行内块 */
      display: inline-block;
      color: white;
    }
  </style>
</head>
​
<body>
​
  <!-- DOM能做什么? -->
  <!-- 
    HTML的本质是 DOM的语法糖写法, 提供了一些简单的功能 -- 静态
    学习DOM, 才能灵活的发挥浏览器的所有功能
​
    HTML属于 阉割版的 DOM, 仅具备少量功能
   -->
​
  <div id="box"></div>
​
  <script>
    // 获取当前的时间, 现在 div#box 里
    // Date
    const now = new Date().toLocaleTimeString()
    console.log('now:', now);
​
    // 目标: 找到 div#box 元素, 然后把 now 放到其内部
    // HTML真正运行时, 会转变成 document 对象
    // 
    // get获取 Element元素 By通过 Id
    var box = document.getElementById('box')
    console.log('box:', box);
    console.dir(box); //dir 查看本质
​
    // innerHTML属性: 代表标签的内容
    box.innerHTML = now
​
    // 定时器: 每秒刷新一次
    setInterval(() => {
      box.innerHTML = new Date().toLocaleString()
    }, 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>
</head>
​
<body>
  <script>
    // 作为一个网页, 哪些元素是一定会有的?
    // head body html
    console.log(document.head);
​
    console.log(document.body);
​
    console.log(document.documentElement); //html
  </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>
</head>
​
<body>
  <button>菜肴</button>
  <button>蔡瑶</button>
  <button>浩南</button>
  <button>浩北</button>
​
  <script>
    // 读取 body中的第一个元素
    // firstChild: 第一个子元素.  子分两类- 文本 和 节点
    console.log(document.body.firstChild); // 回车+空格
​
    // 指定类型: 第一个 元素类型的 孩子
    console.log(document.body.firstElementChild);
​
    // 第二个:  第一个后面的
    console.log(document.body.firstElementChild.nextElementSibling);
    //                          第一个子元素    . 下一个元素
​
    // 获取所有孩子 children
    console.log(document.body.children);
    // 第二个孩子. 下标1的
    console.log(document.body.children[1]);
  </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>
</head>
​
<body>
  <button>家乐入赘</button>
​
  <div style="display: none;">恭喜恭喜, 早生贵子!</div>
​
  <!-- 点击后, 让 上方div隐藏, 即 display 改为 none -->
  <button>被赶出家门</button>
​
  <!-- 点击按钮后, 让 div 显示出来 -->
  <script>
    // 找到 body的孩子中,序号2的元素
    const btn2 = document.body.children[2]
    btn2.onclick = function () {
      // previous: 上一个,前一个
      const d = btn2.previousElementSibling
      d.style.display = 'none' //隐藏
    }
​
​
​
    // 找到按钮元素:  body中的第一个
    const btn = document.body.firstElementChild
    btn.onclick = function () {
      console.log('家乐入赘了!');
​
      const msg = document.body.children[1]
      console.log(msg);
      console.dir(msg); //展开 找到 style 中的display
      // 把display 从 none -> ''
      msg.style.display = ''
    }
  </script>
</body>
​
</html>

通过id查找元素

<!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>通过id查找元素</title>
</head>
​
<body>
  <ul>
    <li id="hao1">浩洋</li>
    <li id="hao2">浩冬</li>
    <li id="hao3">浩南</li>
    <li id="hao4">浩西</li>
  </ul>
​
  <script>
    // 需求: li#hao1  变绿
    const hao1 = document.getElementById('hao1')
    console.dir(hao1) // 展开查看 style 的 color 属性
​
    hao1.style.color = 'green'
​
    // 练习: 找到 li#hao2的元素, 变为红色 red
    const hao2 = document.getElementById('hao2')
    hao2.style.color = 'red'
​
    // id的特殊性: 浏览器默认会把具有id属性的元素自动保存起来
    console.log(hao3);
    hao3.style.color = 'orange'
​
    // 不推荐直接用 id的值, 原因有3
    // 1. 兼容性问题: 并非所有浏览器所有版本都有自动找id的功能
    // 2. 没有代码提示
    // 3. 团队合作时: 照顾有些人不知道能直接用
    hao4.style.color = 'brown'
​
​
  </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 {
      width: 200px;
      height: 200px;
      border: 2px solid gray;
      margin-top: 10px;
      /* 过度时间 */
      transition: 0.5s;
    }
  </style>
</head>
​
<body>
  <button>变红</button>
  <button>变绿</button>
  <button>变蓝</button>
  <button>变圆</button>
​
  <div id="box"></div>
​
  <script>
    // 利用解构语法, 读取子元素: 很常见
    const [btn1, btn2, btn3, btn4] = document.body.children
    const box = document.getElementById('box')
    console.dir(box); // 展开到 style 中找到背景色属性
​
    btn1.onclick = function () {
      box.style.backgroundColor = 'red'
    }
    // btn2: 变绿 green
    // 不推荐用箭头: 以后会有this关键词的问题, 当前场景无所谓
    btn2.onclick = () => box.style.backgroundColor = 'green'
​
    // btn3: 变蓝 blue
    btn3.onclick = function () {
      box.style.backgroundColor = 'blue'
    }
    // btn4: 圆角??
    btn4.onclick = function () {
      box.style.borderRadius = box.style.borderRadius == '50%' ? '' : '50%'
      // style的元素默认值都是 空字符串
    }
  </script>
</body>
​
</html>

总结

DOM:

  • HTML: 就是DOM的一个语法糖写法, 仅提供了小部分功能 -- 静态展示

  • DOM: 才是浏览器中显示的内容的本体. 利用DOM才能制作出 动态变化 的页面, 更加完善

DOM的精髓:找到要操作的元素, 然后修改他的属性

作业

  • 点击家乐按钮, 利用 style 属性, 让 div#box 背景色变绿, 利用 innerHTML 属性, 让其中的文字变为: 欢迎家乐

  • 点击波波按钮, 利用 style 属性, 让 div#box 背景色变蓝, 字体变大到30px, 利用 innerHTML 属性, 让其中的文字变为: 欢迎波波,

  • 点击浪浪按钮, 利用 style 属性, 让 div#box 背景色变紫色, 文字变白色, 粗体, 利用 innerHTML 属性, 让其中的文字变为: 欢迎浪浪

DOM02

DOM: Document Object Model

  • Document: 文档 -- 就是HTML代码

  • Object: 对象 -- HTML代码转换而来的对象

  • Model: 模型 -- HTML 转换成 Object 这种方式

HTML: 就是一种 语法糖 写法, 可以快速的创建出DOM元素

  • 浏览器在阅读HTML后, 会转换成document对象, 最后显示到页面上

  • 浏览器真正展示到页面上的, 是 document对象

  • 学习DOM的目的: 直接操作document 对象, 不再使用普通的HTML

  • HTML只能提供简单的操作操作

  • 可以粗暴理解: DOM犹如玩游戏 开挂, 操作底层代码, 突破限制

查找元素

DOM的重要核心操作: 先查找到元素 -> 然后修改元素的属性

  • 固定元素的查找:

    • document.head

    • document.body

    • document.documentElement: 整个html

  • 按照关系查找

    • 第一个子元素:firstElementChild

    • 所有子元素: children

      • 数组类型, 利用 下标取值来读取某个元素

      • 常见利用数组解构语法, 快速获取多个元素

    • 下一个兄弟元素: nextElementSibling

    • 上一个兄弟元素: previousElementSibling

  • 按照id查找:

    • document.getElementById()

    • 特殊: 浏览器会自动把 id 的元素找到并保存在同名变量中, 可以直接用

      • 不推荐

作业

<!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 {
      width: 200px;
      height: 200px;
      margin-top: 10px;
      border: 2px solid brown;
      transition: 0.5s;
    }
  </style>
</head>
​
<body>
  <button>家乐</button>
  <button>波波</button>
  <button>浪浪</button>
  <div id="box"></div>
​
  <script>
    // 任务: 为每个按钮添加点击事件, 点击后让 div#box 发生变化
    // DOM操作的核心1: 先找到你要操作的元素
    // 所有元素都存储在 document 这个对象里
    const [btn1, btn2, btn3] = document.body.children
    const box = document.getElementById('box')
    console.dir(box) // dir: 用来输出真正的 dom 元素对象
​
    // 核心理念2: 操作元素的属性
    // style的属性, 默认值是 ""  空字符串
​
    // 每个元素,都具备很多事件, 都是以 on 开头的属性
    // on: 当...时
    // onclick: 当点击时
    btn1.onclick = function () {
      box.style.backgroundColor = 'green'
      // innerHTML: 代表标签中的文本
      box.innerHTML = '欢迎家乐'
    }
​
    btn2.onclick = function () {
      box.style.backgroundColor = 'blue'
      box.style.fontSize = '30px'
      box.innerHTML = '欢迎波波'
    }
​
    btn3.onclick = function () {
      box.style.backgroundColor = 'purple'
      box.style.color = 'white'
      box.style.fontWeight = 'bold'
      box.innerHTML = '欢迎浪浪'
    }
  </script>
</body>
​
</html>

通过 标签 和 class 查找

<!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>
</head>
​
<body>
  <div id="box">
    <div>
      <p>Hello</p>
      <p>World</p>
      <div>
        <!-- 通过 name 或 class 来添加特征用于区分 -->
        <!-- name: 为表单元素而生 -- form 提交 -->
        <p class="p-1">欢迎</p>
        <p class="p-1">浪浪</p>
      </div>
    </div>
    <div></div>
  </div>
​
  <script>
    // 按照标签名查找元素:  Tag标签
    const ps = document.getElementsByTagName('p')
    // 查询结果是 类(似)数组: 原型不是数组, 无法使用数组的方法
    // 例如 无法使用 forEach 来遍历 
    console.log(ps);
​
    // for..of : 专业遍历, 适用于 类数组
    // 声明的变量名, 随便起 -- 最好见名知意
    for (const p of ps) {
      p.style.color = 'red'
    }
​
    // 通过 class 名来查找
    const pc = document.getElementsByClassName('p-1')
    console.log(pc);
​
    // 把 pc 中的元素, 背景色变绿
    for (const p of pc) {
      p.style.backgroundColor = 'green'
    }
  </script>
</body>
​
</html>

通过name查找

<!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>通过name查找</title>
</head>
​
<body>
  <div id="box">
    <!-- 表单元素: 具有 name 属性 -->
    <input type="radio" name="sex" id="">
    <input type="radio" name="sex" id="">
    <hr>
    <input type="radio" name="xx" id="">
    <input type="radio" name="xx" id="">
  </div>
​
  <script>
    // 通过 name 来查找元素
    const sexs = document.getElementsByName('sex')
    console.log(sexs);
    // 原型是 NodeList, 非数组 -- 类数组
    // 但是: 原型中有 forEach 方法可以用
​
    // 除了 for..of, 也能用 forEach 遍历
    sexs.forEach(sex => {
      // accentColor: 选中时的高亮色
      sex.style.accentColor = 'red'
    })
​
  </script>
</body>
​
</html>

通过css选择器查找

<!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>通过css选择器查找</title>
</head>
​
<body>
  <!-- 
    css选择器:
    id:  #
    class: .
    属性: [type='password']  选择 type='password' 的元素
    伪类: li:first-child
    标签: tag
    伪元素: div:after
    相邻兄弟: h1+p   <h1><h1><p></p>
    子代: >
    后代: 空格
   -->
  <div id="box">
    <p>波波</p>
    <p>浪浪</p>
    <p>家乐</p>
    <p>浩然</p>
  </div>
​
  <script>
    // 把家乐 变为 粉色
    // css选择器: id=box 的`子`元素中 第三个孩子
    // #box > p:nth-child(3)
​
    // query:查询  selector:选择器
    const p3 = document.querySelector('#box>p:nth-child(3)')
    console.log(p3);
    console.dir(p3);
    p3.style.color = 'pink'
​
    // 把所有 p 标签都添加一个边框
    // all: 代表所有, 查询到满足条件的所有元素
    const ps = document.querySelectorAll('#box > p')
    console.log(ps);
    // 原型 NodeList -- 类数组
    // 但是 有 forEach 方法可以用来遍历
    ps.forEach(p => p.style.border = '1px solid blue')
​
    ps.forEach(p => {
      p.style.border = '1px solid blue'
    })
    // forEach 不懂, 看 JS高级第五天
​
  </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>
</head>
​
<body>
  <div id="box">
    <p>蔡瑶</p>
    <p>李浩洋</p>
    <p>雷家乐</p>
    <p>亮亮</p>
    <p>思琪</p>
  </div>
​
  <!-- 把所有名字是三个字的元素 高亮显示: 文字颜色变红 -->
  <script>
    // 提前思考: 查询出来的东西是 1个 还是 多个(All)
    const ps = document.querySelectorAll('#box > p')
​
    ps.forEach(p => {
      if (p.innerHTML.length == 3) {
        p.style.color = 'red'
      }
    })
  </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>
    table {
      border-collapse: collapse;
      width: 200px;
    }
​
    td,
    th {
      border: 1px solid gray;
      text-align: center;
    }
  </style>
</head>
​
<body>
  <table>
    <thead>
      <tr>
        <th>序号</th>
        <th>姓名</th>
        <th>年龄</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>1</td>
        <td>亮亮</td>
        <td>37</td>
      </tr>
      <tr>
        <td>2</td>
        <td>铭铭</td>
        <td>32</td>
      </tr>
      <tr>
        <td>3</td>
        <td>楠楠</td>
        <td>18</td>
      </tr>
      <tr>
        <td>4</td>
        <td>家乐</td>
        <td>24</td>
      </tr>
    </tbody>
  </table>
​
  <!-- 需求: 把 年龄 大于 30岁的, 整行添加 红色背景色 -->
  <!-- 提示: 利用 parentElement 可以找到元素的父元素 -->
  <script>
    // 年龄:  tr 中的最后一个td
    const ages = document.querySelectorAll('tbody td:last-child')
    console.log(ages)
​
    // age: 箭头函数的形参, 代表 ages 类数组中的具体元素
    // 形参名 是随便起, 但是: 见名知意 是起名原则
    ages.forEach(age => {
      // innerHTML: 用于读取标签中的文本
      // 隐式类型转换: 变量会根据所在的 表达式, 自行转换成合理的类型
      if (age.innerHTML > 30) {
        // 获取某个元素的父元素: parentElement
        const tr = age.parentElement
        console.log(tr);
        tr.style.backgroundColor = 'red'
      }
    })
  </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>
    table {
      border-collapse: collapse;
    }
​
    th,
    td {
      border: 1px solid gray;
      padding: 5px 20px;
    }
  </style>
​
</head>
​
<body>
  <!-- 光标放最后面, 用 ctrl+i 可以弹出生成提示 -->
  <!-- table>(thead>tr>th*4)+(tbody>(tr>td*4)*4) -->
  <table>
    <thead>
      <tr>
        <th>序号</th>
        <th>姓名</th>
        <th>性别</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>1</td>
        <td>亮亮</td>
        <td>男</td>
        <td><button>删除</button></td>
      </tr>
      <tr>
        <td>2</td>
        <td>楠楠</td>
        <td>女</td>
        <td><button>删除</button></td>
      </tr>
      <tr>
        <td>3</td>
        <td>梦瑶</td>
        <td>女</td>
        <td><button>删除</button></td>
      </tr>
      <tr>
        <td>4</td>
        <td>家乐</td>
        <td>男</td>
        <td><button>删除</button></td>
      </tr>
    </tbody>
  </table>
​
  <!-- 要求: 男所在行-blue   女所在行-red -->
</body>
​
</html>

this

<!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>this</title>
</head>
​
<body>
  <!-- 
    this关键词:
    -- 涛哥买了个锤子,  楠姐拿锤子打亮亮
    - function: 锤子的this? -- 楠姐   this代表使用者
    - 箭头函数: 锤子的this?  -- 涛哥   this代表声明时所在作用域中的this
    切记:DOM的事件 要绑定 function, 因为其中this必须指向事件触发时所在的对象
   -->
  <button>11</button>
  <button>22</button>
  <button>33</button>
​
  <script>
    const [btn1, btn2, btn3] = document.body.children
​
    // onclick 在btn1 对象里, 触发时所在对象 btn1 
    btn1.onclick = function () {
      // this: function触发时所在对象
      console.log(this)
    }
​
    // 箭头this: 在哪声明的, 算哪里的this, 后期不变
    // 全局生成: window
    var a = () => { console.log(this) }
    btn2.onclick = a
​
    // 同上: 格式变为合写
    btn3.onclick = () => { console.log(this) }
  </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>
</head>

<body>
  <h2>家乐的相亲会</h2>
  <p>亮灯女嘉宾: 是否要持续关注?</p>
  <button>大乔</button>
  <button>小乔</button>
  <button>蔡文姬</button>
  <button>貂蝉</button>
  <button>西施</button>

  <script>
    // DOM核心1: 先找到你要操作的元素
    const btns = document.querySelectorAll('button')
    btns.forEach(btn => btn.onclick = function () {
      // this: 代表触发时所在对象
      this.remove()
    })
  </script>
</body>

</html>

class

<!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>class操作</title>

  <style>
    #box {
      width: 200px;
      height: 200px;
      border: 2px solid gray;
      transition: 0.5s;
      margin-top: 10px;
    }

    /* class选择器 . */
    .suc {
      background-color: green;
    }

    .fail {
      background-color: red;
    }
  </style>
</head>

<body>
  <!-- css样式有两种做法:  style 和 class -->
  <!-- style: 内联样式, 适合非常少量的css修改 -- 实际开发很少用 -->
  <!-- class: 内部样式, 适合实际开发 -->
  <button>成功</button>
  <button>失败</button>
  <div id="box"></div>

  <script>
    const [btn1, btn2, box] = document.body.children
    console.dir(box) //到后台找到 class 相关的属性

    btn1.onclick = function () {
      // className: 因为JS中 class是关键词, 代表 JAVA的 类
      // 所以 JS 中, 改名为 className
      box.className = 'suc'
    }
    // 练习: 完成失败的操作
    btn2.onclick = function () {
      box.className = 'fail'
    }
  </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 {
      /* 用户-可选中文本: 不能 */
      user-select: none;
    }

    #box>span {
      display: inline-block;
      padding: 5px 15px;
      background-color: #bbb;
      border-radius: 5px;
    }

    /* span:标签  .cur: class='cur' */
    /* span.cur : <span class='cur'  代表 span带有 cur */
    #box>span.cur {
      background-color: orange;
      color: white;
    }
  </style>
</head>

<body>
  <div id="box">
    <span class="cur">黄焖鸡</span>
    <span>KFC</span>
    <span>麦当劳</span>
    <span>水煮鱼</span>
    <span>炒饭</span>
  </div>

  <script>
    // 牢记: DOM操作的核心 -- 先找到你要操作的元素
    const spans = document.querySelectorAll('#box span')
    spans.forEach(span => span.onclick = function () {
      // this.className = 'cur'
      // if (this.className == '') {
      //   this.className = 'cur'
      // } else {
      //   this.className = ''
      // }
      this.classList.toggle('cur')
      console.log(this.classList);
      // classList: 一个工具箱, 存储了一些快捷的操作class的方法
      // 常用方法:
      // - add: 添加样式
      // - remove: 删除
      // - replace: 替换
      // - toggle: 切换 -- 有就删, 没有就加
    })
  </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 {
      user-select: none;
    }

    #box>span {
      display: inline-block;
      background-color: #bbb;
      line-height: 80px;
      width: 80px;
      text-align: center;
      transition: 0.3s;
    }

    /* cur: 自定义的, 最优单词 active(激活) */
    #box>span.cur {
      border-radius: 50%;
      background-color: orange;
      color: white;
    }
  </style>
</head>

<body>
  <h3>请选择英雄:</h3>
  <div id="box">
    <span>德莱文</span>
    <span>万豪</span>
    <span>提莫</span>
    <span>纳尔</span>
    <span>猫咪</span>
  </div>

  <script>
    const spans = document.querySelectorAll('#box span')

    spans.forEach(span => span.onclick = function () {
      // 唯一性的选择: 先找到之前的带有 cur 样式的元素, 删掉样式
      const cur = document.querySelector('.cur')
      // 如果 cur 为真, 说明存在, 再执行
      // if (cur) cur.classList.remove('cur')

      // 实际工作: 更喜欢用逻辑短路写法
      cur && cur.classList.remove('cur')
      // 逻辑与: 全真则为真 -- 前方表达式是真, 后方才能继续执行
      // cur: 如果是假  false && xxx :  xxx 就不会执行
      // 家乐要嫁人- 要求:  有房 && 有车 && 有钱
      // 必须前方条件满足, 才会验证后续的条件

      // 搜狗输入法: shift 按键 切换中英文
      this.classList.add('cur')
    })
  </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>
    #pages {
      user-select: none;
      background-color: #f5f5f6;
      padding: 20px;
    }

    #pages>span {
      background-color: white;
      color: #4e6ef2;
      display: inline-block;
      border-radius: 4px;
      line-height: 40px;
      width: 40px;
      text-align: center;
    }

    #pages>span.cur {
      background-color: #4e6ef2;
      color: white;
    }
  </style>
</head>

<body>
  <div id="pages">
    <span class="cur">1</span>
    <span>2</span>
    <span>3</span>
    <span>4</span>
    <span>5</span>
  </div>

  <script>
    const spans = document.querySelectorAll('#pages span')

    spans.forEach(span => span.onclick = function () {
      // 保障唯一性:  新的添加前, 要移除旧的

      // 参数是 css选择器  .cur 代表 class=cur
      const cur = document.querySelector('.cur')
      // 参数是 class名
      cur.classList.remove('cur')
      // 区别: 当前练习 默认第一项就是 class='cur', 不存在搜索不到的情况, 所以不需要判断 cur 是否存在

      this.classList.add('cur')
    })
  </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>
    #dian {
      user-select: none;
      background-color: #888;
      padding: 10px;
    }

    #dian>span {
      display: inline-block;
      width: 20px;
      height: 20px;
      border-radius: 10px;
      background-color: white;
      transition: width 0.7s;
    }

    #dian>span.cur {
      background-color: #206cfe;
      width: 50px;
    }
  </style>
</head>

<body>
  <div id="dian">
    <span class="cur"></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
  </div>

  <script>
    // DOM核心宗旨:找到你要操作的元素
    const spans = document.querySelectorAll('#dian span')

    // 所有事件
    // https://www.w3school.com.cn/jsref/dom_obj_event.asp
    spans.forEach(span => span.onmouseenter = function () {
      document.querySelector('.cur').classList.remove('cur')

      this.classList.add('cur')
    })
  </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 {
      width: 200px;
    }

    #box>div {
      border: 2px solid gray;
      background-color: green;
      height: 100px;
    }

    #box>div:last-child {
      display: none;
    }

    #box>div:last-child.open {
      display: block;
    }
  </style>
</head>

<body>
  <div id="box">
    <button>展开</button>
    <div></div>
    <div></div>
  </div>

  <script>
    // DOM操作的核心: 先找到你要操作的元素
    // 做什么: 点击按钮 -> 切换 最后一个div的显示 open

    // 预判: 要查找的元素有几个  1个 ??  多个??
    const btn = document.querySelector('button')
    btn.onclick = function () {
      const d = document.querySelector('#box>div:last-child')
      // 切换样式 open:  工具箱 classLis中, toggle
      d.classList.toggle('open')

      // 通过判断是否含有 open 样式, 来决定按钮的文字
      // contains: 包含, 用于判断是否包含某个样式
      this.innerHTML = (d.classList.contains('open') ? '收起' : '展开')
    }
  </script>
</body>

</html>

今日内容回顾

DOM的用途主要在于实战

  • DOM核心点1: 学会如何找到你要操作的元素

    • 固定的: head body documentElement

    • 按照关系:

      • children

      • firstElementChild

      • parentElement

      • nextElementSibling :隔壁的兄弟

    • 按照特征查找(除了id 其他很少用)

      • id

      • class

      • 标签名

      • name

    • 利用 css选择器 查找

      • querySelector: 查单个元素, 返回值是 元素本身

      • querySelectorAll: 查多个元素, 返回值是 类数组, 有forEach可以用

  • class

    • className: 就是 class 属性本身

    • classList: 一个工具箱, 存放了很多操作class的方法, 更加易用!

      • add: 添加样式

      • remove: 移除样式

      • toggle: 切换样式

      • contains: 是否有某个样式

作业

点击之后变色高亮手游休闲, 悬浮时是 娱乐天地 的样子

同时只能一个高亮


鼠标进入时: mouseenter 会展开当前项. 本质是切换 open 样式

提示: 刚开始每一条

<div id='box'>
    <div>
        <div>标题</div>
        <div>说明 -- 初始隐藏</div>
    </div>
    <div>
        <div>标题</div>
        <div>说明 -- 初始隐藏</div>
    </div>
    <div>
        <div>标题</div>
        <div>说明 -- 初始隐藏</div>
    </div>
</div>

DOM03

复习

DOM的核心操作2件事:

  • 查找到你要操作的元素

    • 固定元素的查找: head body documentElement

    • 按照关系

      • chilren: 子元素们

      • parentElement: 父元素

      • firstElementChild: 第一个子元素

      • nextElementSibling: 下一个兄弟元素

      • previousElementSibling: 上一个兄弟元素

    • 按照特征

      • id : 唯一性, 结果只有一个

      • class: 多个

      • 标签 tag: 多个

      • name: 多个

    • 通过 css选择器最常用

      • querySelector: 单个元素

      • querySelectorAll: 多个元素

  • 操作元素的属性

    • style: 内联样式

    • class:

      • className: 就是class属性本身

      • classList: 工具箱 -- 存放了很多操作class的方法

        • add: 添加

        • remove: 移除

        • toggle: 切换

        • contains: 判断是否存在

    • 事件: 都是 on 开头

      • onclick: 点击

      • onmouseenter: 鼠标进入

作业

<!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 {
      user-select: none;
      background-color: #f2f5f6;
      padding: 10px;
    }
​
    #box>span {
      display: inline-block;
      line-height: 40px;
      width: 100px;
      border-radius: 20px;
      background-color: white;
      text-align: center;
      color: #666;
      margin: 0 5px;
      border: 1px solid #eee;
    }
​
    #box>span:hover {
      border-color: #ff5d23;
      color: #ff5d23;
    }
​
    #box>span.active {
      color: white;
      background-color: #ff5d23;
      border-color: #ff5d23;
    }
  </style>
</head>
​
<body>
  <div id="box">
    <span class="active">网游竞技</span>
    <span>单机热游</span>
    <span>手游休闲</span>
    <span>娱乐天地</span>
    <span>颜值</span>
    <span>科技文化</span>
  </div>
​
  <script>
    // 分辨 要查找的元素是 1个 还是 多个??
    const spans = document.querySelectorAll('#box span')
​
    spans.forEach(span => span.onclick = function () {
      // 删除之前的高亮项
      document.querySelector('.active').classList.remove('active')
      // 当前点击项高亮
      this.classList.add('active')
    })
  </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 {
      background-color: #888;
      color: white;
      width: 300px;
    }
​
    #box>div {
      padding: 10px;
    }
​
    #box>div>div:last-child {
      display: none;
    }
​
    /* 带有 open 样式, 应该显示: 优先级权重 open会优先 */
    #box>div.open>div:last-child {
      display: block;
    }
​
    #box>div.open>div:first-child {
      color: orange;
      font-size: 1.2em;
    }
​
    #box>div.open {
      background-color: #666;
    }
  </style>
</head>
​
<body>
  <div id="box">
    <div class="open">
      <div>英雄联盟钻粉福利周11</div>
      <div>开通钻粉领取福利周边~!</div>
    </div>
    <div>
      <div>英雄联盟钻粉福利周22</div>
      <div>开通钻粉领取福利周边~!</div>
    </div>
    <div>
      <div>英雄联盟钻粉福利周33</div>
      <div>开通钻粉领取福利周边~!</div>
    </div>
  </div>
​
  <script>
    const items = document.querySelectorAll('#box>div')
​
    items.forEach(item => item.onmouseenter = function () {
      document.querySelector('.open').classList.remove('open')
      this.classList.add('open')
    })
  </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 {
      background-color: lightblue;
      width: 400px;
      user-select: none;
    }
​
    #box>img {
      width: 100%;
    }
​
    body {
      background-color: #eee;
    }
​
    #box>div>img {
      width: 23%;
      /* transparent: 透明 */
      border: 2px solid transparent;
    }
​
    #box>div>img.active {
      border-color: red;
    }
  </style>
</head>
​
<body>
  <div id="box">
    <img src="./imgs/1_lg.jpg" alt="">
    <div>
      <!-- 自定义属性: 存储小图对应的大图名 -->
      <img data-big="1_lg.jpg" class="active" src="./imgs/1.sm.jpg" alt="">
      <img data-big="2.lg.jpg" src="./imgs/2.sm.jpg" alt="">
      <img data-big="3.lg.jpg" src="./imgs/3.sm.jpg" alt="">
      <img data-big="4.lg.jpg" src="./imgs/4.sm.jpg" alt="">
    </div>
  </div>
​
  <script>
    const imgs = document.querySelectorAll('#box>div>img')
    const big_img = document.querySelector('#box>img')
    console.dir(big_img) // 查看其 src 属性
​
    imgs.forEach(img => img.onmouseenter = function () {
      const active = document.querySelector('#box .active')
      active.classList.remove('active')
​
      // 当前项.工具箱.添加工具()
      this.classList.add('active')
​
      // 读取当前项中, 存储的自定义属性 big, 即大图的名字
      // 图片使用时, 需要有路径, 不能光有名字, 所以要拼接
      big_img.src = './imgs/' + this.dataset.big
    })
  </script>
</body>
<!-- 
  大图1张 1000KB
  小图1张 100KB
​
  5张图
  -- 假设: 全用大图,  消耗 5000KB
  -- 假设: 5个小图 + 1个大图  消耗 1500KB
  -- --- 用户滑动时: 临时请求大图
  ------ 优点: 首次加载速度快; 如果用户没看别的, 省3500kb流量
 -->
​
</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>
</head>
​
<body>
  <!-- 每个DOM元素, 系统都提供了很多固有属性 -- 系统属性 -->
  <!-- 可以添加 自定义属性: 以 data- 开头 -->
  <a href="http://www.baidu.com" id="a1" class="danger" title="百度一下, 精彩即来" target="_blank" data-xx="11" data-yy="22"
    data-zz="33">百度一下</a>
​
  <script>
    const a1 = document.getElementById('a1')
    console.dir(a1); // 试一试, 能否在后台找到自定义属性在哪里?
    // dataset: 专门存储利用 data- 声明的自定义属性
​
    // 读取自定义属性
    console.log(a1.dataset.xx);
    console.log(a1.dataset.yy);
    console.log(a1.dataset.zz);
  </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>
    #tabs>div:first-child {
      border-bottom: 1px solid red;
      background-color: #f7f7f7;
      color: #666;
      padding: 0 1px 1px 1px;
      user-select: none;
    }
​
    #tabs>div:first-child>span {
      padding: 10px 20px;
      display: inline-block;
    }
​
    #tabs>div:first-child>span.active {
      background-color: red;
      color: white;
    }
​
    #tabs>div:last-child>div {
      border: 1px solid gray;
      height: 300px;
      padding: 10px;
      background-color: #eee;
    }
​
    /* :not(): 不是,  不是 .active 的, 都隐藏 */
    #tabs>div:last-child>div:not(.active) {
      display: none;
    }
  </style>
</head>
​
<body>
  <div id="tabs">
    <div>
      <!-- 利用自定义属性, 存储 标题对应的内容id -->
      <span data-id="tab1" class="active">商品介绍</span>
      <span data-id="tab2">规格与包装</span>
      <span data-id="tab3">售后保障</span>
    </div>
    <div>
      <div id="tab1" class="active">商品介绍...</div>
      <div id="tab2">规格与包装...</div>
      <div id="tab3">售后保障...</div>
    </div>
  </div>
​
  <script>
    const tabs = document.querySelectorAll('#tabs>div:first-child>span')
​
    tabs.forEach(tab => tab.onclick = function () {
      const s = '#tabs>div:first-child>span.active'
      document.querySelector(s).classList.remove('active')
​
      this.classList.add('active')
​
      // 把之前带有 .active 的详情, 移除激活态
      document.querySelector('#tabs div.active').classList.remove('active')
​
      // 读取当前点击项中存储的 自定义属性 id
      const id = this.dataset.id
      // 通过id 找到对应的详情元素
      // id是变量, 需要用模板字符串拼接
      const detail = document.querySelector(`#tabs #${id}`)
      detail.classList.add('active')
    })
  </script>
​
  <!-- 
    总结: 可以利用自定义属性, 让不同元素之前产生联系
    实现: 操作A元素, 让B元素产生变化
   -->
</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 {
      user-select: none;
    }
​
    #box>div>span {
      display: inline-block;
      width: 180px;
      line-height: 50px;
      text-align: center;
      border-radius: 4px;
      border: 1px solid gray;
      color: gray;
      margin: 0 10px 10px 0;
    }
​
    #box>div>span.active {
      border-color: red;
      color: red;
    }
​
    #box>h1 {
      color: red;
    }
  </style>
</head>
​
<body>
  <div id="box">
    <h1>4899</h1>
    <div>
      <span data-price="4899" class="active">12GB+512GB</span>
      <span data-price="3999">8GB+256GB</span>
      <span data-price="3699">8GB+128GB</span>
      <span data-price="4399">12GB+256GB</span>
    </div>
  </div>
​
  <script>
    const items = document.querySelectorAll('#box>div>span')
    const h1 = document.querySelector('#box>h1')
​
    items.forEach(item => item.onclick = function () {
      document.querySelector('#box .active').classList.remove('active')
​
      this.classList.add('active')
​
      //读取当前项的 自定义属性 price
      const price = this.dataset.price
      h1.innerHTML = price //设置到 h1 的文本
    })
  </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>
</head>
​
<body>
  <input type="text" id="">
​
  <script>
    // 输入框的相关事件:
    const inp = document.querySelector('input')
​
    // 1. 获得焦点 focus
    inp.onfocus = function () {
      console.log('focus: 光标闪烁, 获得焦点');
    }
​
    // 2. 失去焦点 blur
    inp.onblur = function () {
      console.log('blur: 失去焦点');
    }
​
    // 3. 内容变化 change
    // 前提: 输入框内容变化 然后 回车或失去焦点后触发
    inp.onchange = function () {
      // value: 此属性中存储的是 输入框的值
      console.log('内容变化:', this.value);
    }
​
    // 4. 内容实时变更 input
    inp.oninput = function () {
      console.log('实时:', this.value);
    }
​
    // 5. 键盘事件 keyup
​
    // 事件参数: 当事件触发时,会自动携带事件相关的所有信息
    inp.onkeyup = function (e) {
      // 事件参数一直都有, 之前没用上. 显示要用, 所以声明参数接收
      // 形参名随便, 但是最好有含义  event:事件   简称e
      console.log(e);
      // keyCode: 按键的编号
      // 利用 keyCode 来判断用户按下了什么按键
      // keyCode == 13 代表回车
      if (e.keyCode == 13) {
        console.log('回车被点...');
        // 场景: 在输入框中 按回车, 自动发送搜索请求之类的...
      }
    }
  </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 {
      user-select: none;
    }
​
    #box>div {
      display: inline-block;
    }
​
    #box>div>span {
      font-size: 0.7em;
      color: white;
      display: inline-block;
      border-radius: 3px;
      padding: 3px 5px;
      transform: scale(0.8);
    }
​
    /* 只有激活的才显示: 不带有 active 样式的,都隐藏 */
    #box>div>span:not(.active) {
      display: none;
    }
​
    #box>div>span.ok {
      background-color: green;
    }
​
    #box>div>span.err {
      background-color: red;
    }
​
    #box>div>span.info {
      background-color: gray;
    }
  </style>
</head>
​
<body>
  <div id="box">
    <span>手机号:</span>
    <input type="text" placeholder="请输入您的手机号">
    <div>
      <span class="err">手机号格式不正确</span>
      <span class="err">手机号不能为空</span>
      <span class="ok">该手机号可以使用</span>
      <span class="info">请输入合法的手机号</span>
    </div>
  </div>
​
  <script>
    const inp = document.querySelector('#box input')
​
    // 获得焦点: 让 .info 显示 
    inp.onfocus = function () {
      // bug修复: 如果手机号已经对了, 则不做处理
      if (/^1[3-9]\d{9}$/.test(this.value)) return
​
      const active = document.querySelector('#box .active')
      // active:不一定存在, 使用前先判断为真
      active && active.classList.remove('active')
​
      const info = document.querySelector('#box .info')
      info.classList.add('active')
    }
​
    // 失去焦点
    inp.onblur = function () {
      // 删除之前激活的
      document.querySelector('#box .active').classList.remove('active')
​
      // 判断:如果输入框是空的
      if (this.value == '') {
        const empty = document.querySelector('#box .err:nth-child(2)')
        empty.classList.add('active')
        return //停止函数的执行, 后续代码不生效
      }
​
      // 正则验证手机号格式 /^1[3-9]\d{9}$/
      if (/^1[3-9]\d{9}$/.test(this.value)) {
        const ok = document.querySelector('#box .ok')
        ok.classList.add('active')
      } else {
        const err = document.querySelector('#box .err:first-child')
        err.classList.add('active')
      }
    }
  </script>
​
  <!-- 
    书写代码完成一个功能时:
    - 思路: 先把要展示的内容都写出来, 然后根据条件判断 哪些显示 哪些不显示
    ---- 获取焦点:  清空之前的激活, 显示提示info
    ---- 失去焦点:
    ------- 为空: 显示 为空的报错
    ------- 手机号格式错误: 显示 格式错误的报错
    ------- 手机号格式正确: 显示 格式正确的提示
    
    - 代码: 需要熟练度 -- 只能多练
   -->
</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 {
      user-select: none;
    }

    #box>div {
      display: inline-block;
    }

    #box>div>span {
      display: inline-block;
      padding: 5px 10px;
      color: white;
      border-radius: 3px;
    }

    #box>div>span.info {
      background-color: gray;
    }

    #box>div>span.ok {
      background-color: green;
    }

    #box>div>span.err {
      background-color: red;
    }

    #box>div>span:not(.active) {
      display: none;
    }
  </style>
</head>

<body>
  <div id="box">
    <span>用户名:</span>
    <input type="text" placeholder="请输入用户名">
    <div>
      <span class="info">用户名长度在6到9位之间</span>
      <span class="ok">用户名可以使用</span>
      <span class="err">用户名不能为空</span>
      <span class="err">用户名位数错误!</span>
    </div>
  </div>

  <script>
    const inp = document.querySelector('#box input')

    inp.onfocus = function () {
      // 获得焦点时, 也要清除之前的高亮项目
      // ES6提供的语法:  变量?.    如果变量是真的, 才会继续执行
      // 中文的ES6教程: https://es6.ruanyifeng.com/
      document.querySelector('#box .active')?.classList.remove('active')

      const info = document.querySelector('#box .info')
      info.classList.add('active')
    }

    inp.onblur = function () {
      document.querySelector('#box .active').classList.remove('active')

      if (this.value == '') {
        const err = document.querySelector('#box .err:nth-child(3)')
        err.classList.add('active')
        return // 防止为空, 导致后续的 位数错误也显示
      }

      if (this.value.length >= 3 && this.value.length <= 9) {
        const ok = document.querySelector('#box .ok')
        ok.classList.add('active')
      } else {
        const err = document.querySelector('#box .err:last-child')
        err.classList.add('active')
      }
    }

  </script>
</body>

</html>

change事件

<!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>change事件</title>
  <style>
    .btn {
      display: inline-block;
      width: 300px;
      text-align: center;
      background-color: #72b134;
      border-radius: 3px;
      line-height: 30px;
      color: white;
      user-select: none;
    }

    .btn:active {
      opacity: 0.7;
    }

    /* 联合在一起写: 代表同时具备 */
    .btn.disabled {
      background-color: #aaa;
      /* 指针-事件们: 一个都不留;    去掉所有鼠标响应 */
      pointer-events: none;
    }
  </style>
</head>

<body>
  <div id="box">
    <!-- label被点击时, 会触发其子元素的点击事件 -->
    <label>
      <input type="checkbox">
      <span>我已阅读并同意用户注册协议</span>
    </label>
    <br>
    <div class="btn disabled">提交注册</div>
  </div>

  <script>
    // 检测: 勾选按钮的 状态变化
    const btn = document.querySelector('.btn')
    const chb = document.querySelector('#box input')

    // change: 值发生变化
    chb.onchange = function () {
      console.dir(this); // 检查 : checked 属性的值
      console.log('checked:', this.checked);
      // if (this.checked) {  //勾选状态, 删除disabled
      //   btn.classList.remove('disabled')
      // } else {
      //   btn.classList.add('disabled')
      // }

      this.checked ? btn.classList.remove('disabled') : btn.classList.add('disabled')

      // []: 其中书写JS代码
      // btn.classList[this.checked ? 'remove' : 'add']('disabled')

      // 下方3行代码同含义
      // btn.classList.add('xxx')
      // btn.classList['add']('xxx')

      // var x = 'add'
      // btn.classList[x]('xxx')
    }
  </script>
</body>

</html>

今日知识点

  • 图片的 src 属性

  • 自定义属性: data- 开头, 存储在 dataset属性里

  • 输入框的事件

    • focus

    • blur

    • change

    • input

    • keyup

作业

作业1: 轮播图的参考: 首页

图片从今日提供的压缩包中获取

  • 先把 小圆点的效果完成

  • 关于图片: css必须用 绝对定位来书写 position:absolute

  • 4张图片需要 层叠在一起, 其中只有 带有 active 样式的图片才显示

    • 为图片添加过度transition:0.5s

    • 图片把 opacity 透明度改为0, 只有 active的透明度才是 1 即显示

  • 每个小圆点有个自定义属性,data-index, 值是对应的图片的 序号, 即nth-child(??)

    <div id='banner'>
        <div>
            <img class='active' src='.....'>
            <img src='.....'>
            <img src='.....'>
            <img src='.....'>
        </div>
        <div>
            <span data-index='1' class='active'></span>
            <span data-index='2'></span>
            <span data-index='3'></span>
            <span data-index='4'></span>
        </div>
    </div>

DOM04

复习

  • 输入框的相关事件

    • focus: 获得焦点

    • blur: 失去焦点

    • change: 内容变化时 -- 回车/失去焦点

    • input: 实时变化监听

    • keyup: 键盘的按键抬起

      • 通过事件参数 e 来读取当前是哪个按键触发的, 回车keyCode = 13

  • 自定义属性

    • data- : 存储在 dataset

    • 用途

      • 存储一些相关的属性 或者 关键其他的元素们

作业

<!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>
    /* 绝对定位: 父相子绝 */
    #banner {
      border: 2px solid red;
      user-select: none;
      width: 600px;
      height: 300px;
      position: relative;
    }
​
    #banner>div:last-child {
      position: absolute;
      bottom: 5px;
      width: 100%;
      text-align: center;
    }
​
    #banner>div:first-child {
      position: relative;
      height: 100%;
    }
​
    #banner>div>img {
      position: absolute;
      width: 100%;
      height: 100%;
      transition: 0.5s;
    }
​
    /* 除了 .active 之外, 都要透明 */
    #banner img:not(.active) {
      opacity: 0;
    }
​
    #banner span {
      display: inline-block;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background-color: #cccccc;
      margin: 0 4px;
    }
​
    #banner span.active {
      background-color: orange;
    }
  </style>
</head>
​
<body>
  <div id="banner">
    <div>
      <img class="active" src="./imgs/banner1.png" alt="">
      <img src="./imgs/banner2.png" alt="">
      <img src="./imgs/banner3.png" alt="">
      <img src="./imgs/banner4.png" alt="">
    </div>
    <div>
      <!-- 利用自定义属性, 记录小圆点对应的图是第几个 -->
      <span data-index="1" class="active"></span>
      <span data-index="2"></span>
      <span data-index="3"></span>
      <span data-index="4"></span>
    </div>
  </div>
​
  <script>
    // DOM核心: 先查出你要操作的元素
    // 我要 操作小圆点 -> 就要把小圆点查出来 -> 数 4 个 -> all
    const dians = document.querySelectorAll('#banner span')
    dians.forEach(dian => dian.onmouseenter = function () {
      document.querySelector('#banner span.active').classList.remove('active')
​
      this.classList.add('active')
​
      const index = this.dataset.index
      // index存储的是第几个, 例如 1 2 3 4
      const img = document.querySelector(`#banner img:nth-child(${index})`)
​
      // 去掉之前 激活的图片, 为当前图片添加激活
      document.querySelector('#banner img.active').classList.remove('active')
      img.classList.add('active')
    })
  </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>
    #banner {
      user-select: none;
      border: 2px solid red;
      width: 400px;
      overflow: hidden;
      position: relative;
    }
​
    #banner>div:last-child {
      position: absolute;
      width: 100%;
      text-align: center;
      bottom: 5px;
    }
​
    #banner>div:first-child {
      display: flex;
    }
​
    #banner img {
      width: 100%;
      height: 160px;
      transition: 0.5s;
    }
​
    /* 移动第一个图片的 左侧外边距, 让图片一起动 */
    #banner img:first-child {
      /* margin-left: -400px; */
    }
​
    #banner span {
      display: inline-block;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background-color: #cccccc;
      margin: 0 4px;
    }
​
    #banner span.active {
      background-color: orange;
    }
  </style>
</head>
​
<body>
  <div id="banner">
    <div>
      <img class="active" src="./imgs/banner1.png" alt="">
      <img src="./imgs/banner2.png" alt="">
      <img src="./imgs/banner3.png" alt="">
      <img src="./imgs/banner4.png" alt="">
    </div>
    <div>
      <span data-index="0" class="active"></span>
      <span data-index="1"></span>
      <span data-index="2"></span>
      <span data-index="3"></span>
    </div>
  </div>
​
  <script>
    const dians = document.querySelectorAll('#banner span')
    dians.forEach(dian => dian.onmouseenter = function () {
      document.querySelector('#banner span.active').classList.remove('active')
​
      this.classList.add('active')
​
      const index = this.dataset.index
      const img = document.querySelector('#banner img:first-child')
      img.style.marginLeft = -400 * index + 'px'
    })
​
    // 定时器实现自动滚动
    setInterval(() => {
      // 获取当前的项目, 然后触发其下一项
      const active = document.querySelector('#banner span.active')
      // 下一个小圆点
      let next_dian = active.nextElementSibling
      console.log(next_dian);
      // 如果 next_dian 是null, 说明已经是最后一个, 则回到第一个
      // if (next_dian == null) {
      // 激活的元素.父元素.第一个子元素
      // next_dian = active.parentElement.firstElementChild
      // }
​
      // 进阶语法: 逻辑短路,  在逻辑或中, 前面是假的, 则会执行后续代码;
      next_dian || (next_dian = active.parentElement.firstElementChild)
​
      // 直接触发小圆点的 mouseenter 
      next_dian.onmouseenter()
    }, 2000);
​
    // 下一个 和 上一个 按钮的逻辑, 与自动滚动几乎一样, 仅是利用点击触发
    // 更加细节的轮播图: 后续采用 第三方 swiper 实现
  </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>
</head>
​
<body>
  <div id="box">
    <a href="">百度一下</a>
  </div>
​
  <div id="app">Welcome</div>
​
  <script>
    const box = document.getElementById('box')
​
    console.log(box.innerHTML) // HTML标签 + 文本
    console.log(box.innerText) // 文本
​
    // 是否相同?
    // 如果标签的内容是`纯文本`: HTML和 Text 读取结果相同
    console.log(app.innerHTML == app.innerText);
    console.log(app.innerHTML) // 其中没有HTML标签, 只有文本
    console.log(app.innerText) // 只读文本
​
​
    // 设置内容:
    box.innerHTML = '<h1>Hello</h1>' // 值作为HTML代码解析
    app.innerText = '<h1>Hello</h1>' // 值作为普通文本显示
  </script>
</body>
​
</html>

数组转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>数组转html</title>
</head>
​
<body>
  <div id="box"></div>
​
  <script>
    const data = ['vue', 'react', 'angular', 'uniapp']
    // 要求: 把数据放到按钮里, 显示在 div#box 中
​
    // 高阶函数: map 映射. 把数组中的元素 映射成 HTML代码
    const els = data.map(v => `<button>${v}</button>`)
    console.log(els);
​
    // 如何把数组的元素, 拼接成字符串: join
    console.log(els.join('')) //默认是逗号间隔, 主动传递 ''
​
    box.innerHTML = els.join('') // 参数代表用什么间隔
​
    // 套路: 先用 map 把数组中的元素转换成 HTML 代码
    // 然后利用 join 拼接到一起, 设置给 innerHTML
  </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>
    .tag {
      display: inline-block;
      width: 70px;
      line-height: 30px;
      text-align: center;
      background-color: #f6f7f8;
      border: 1px solid #ddd;
      margin: 0 10px 10px 0;
      border-radius: 4px;
    }
  </style>
</head>
​
<body>
  <div id="box"></div>
​
  <script>
    const data = ['番剧', '国创', '综艺', '动画', '鬼畜', '电影', '电视剧', '纪录片', '游戏', '音乐']
​
    // 要求拼接成: <span class='tag'>xxx</span>
    // 然后自己书写一个 .tag 的class来设置样式
    const a = data.map(y => `<span class='tag'>${y}</span>`)
    box.innerHTML = a.join('')
  </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>
    a {
      text-decoration: none;
      padding: 4px;
      display: inline-block;
      color: gray;
    }
  </style>
</head>
​
<body>
  <div id="box"></div>
​
  <script>
    const data = [
      { title: '新闻', href: 'http://news.baidu.com/' },
      { title: 'hao123', href: 'https://www.hao123.com/' },
      { title: '地图', href: 'https://map.baidu.com/' },
      { title: '贴吧', href: 'https://tieba.baidu.com/' },
      { title: '视频', href: 'https://haokan.baidu.com/' },
    ]
    // 示例: <a href="http://news.baidu.com/">新闻</a>
​
    // 参数解构: ES6  -- JS高级的第五天
    const a = data.map(({ title, href }) => `<a href="${href}">${title}</a>`)
    box.innerHTML = a.join('')
​
    const b = data.map(v => {
      return `<a href='${v.href}'>${v.title}</a>`
    })
    box.innerHTML = b.join('')
  </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>
    .red {
      height: 600px;
      background-color: red;
      width: 600px;
    }
​
    .blue {
      height: 400px;
      width: 400px;
      background-color: blue;
    }
​
    .green {
      height: 200px;
      width: 200px;
      background-color: green;
    }
  </style>
</head>
​
<body>
  <!-- 
    冒泡机制: 
    - 当子元素上触发事件, 会自动通知父元素, 触发其相同的事件
    - 事件参数e: 其中的target属性存储了 事件触发的当事人
    - 利用 stopPropagation() 可以停止冒泡
   -->
​
  <div class="red">
    <div class="blue">
      <div class="green"></div>
    </div>
  </div>
​
  <script>
    // 事件冒泡机制: 当子元素上发生某个事件, 会传递给父元素 
    // 通俗: 找家长  找老师... -- 家乐被人打了, 家乐找爸爸告状
​
    const red = document.querySelector('.red')
    // 凡是事件触发时,都会自动带有事件参数: 包含了事件触发时的各种信息
    red.onclick = function (e) {
      // 红色触发的点击事件, 不一定是自己触发的, 有可能是子元素传递
      console.log(e) // 找到target属性
​
      // e.target: 代表触发事件的 当事人
​
      console.log('red被点击');
    }
​
    const blue = document.querySelector('.blue')
    blue.onclick = function () {
      console.log('blue被点击');
    }
​
    const green = document.querySelector('.green')
    green.onclick = function (e) {
      // stop:停止  propagation: 传播
      e.stopPropagation()
      // 事件的冒泡机制被终止, 不会通知父元素
​
      console.log('green被点击');
    }
  </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 {
      padding: 10px;
      background-color: #ddd;
    }
​
    #box>span {
      display: inline-block;
      border-radius: 3px;
      padding: 5px 10px;
      background-color: #aaa;
      margin: 0 10px 10px 0;
    }
  </style>
</head>
​
<body>
  <!-- 事件委托: 元素的事件 交由 父元素来管理, 委托给父元素 -->
  <!-- 适用场景: 动态新增的子元素 -->
  <input type="text" name="" id="">
​
  <div id="box">
    <span>百度</span>
    <span>京东</span>
    <span>淘宝</span>
    <span>阿里</span>
  </div>
​
  <script>
    const items = document.querySelectorAll('#box span')
    items.forEach(item => item.onclick = function () {
      this.remove()
    })
​
    const inp = document.querySelector('input')
    inp.onkeyup = function (e) {
      // 键盘事件的 keyCode 属性, 13代表回车
      if (e.keyCode == 13) {
        // 累加
        box.innerHTML += `<span>${this.value}</span>`
        this.value = ''
      }
    }
​
    // 问题: 新增每个元素 都需要重新为其添加 点击事件, 过于繁琐
    // 做法: 给父元素添加
    box.onclick = function (e) {
      // target: 事件触发的当事人
      console.log('box被点击:', e.target);
      // 查看其属性, 哪个能分辨出span还是div
      console.dir(e.target)
      if (e.target.tagName == 'SPAN') {
        e.target.remove()
      }
    }
  </script>
</body>
​
</html>

手动创建DOM元素

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

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>手动创建DOM元素</title>
  <style>
    #box {
      padding: 10px;
      background-color: limegreen;
    }
  </style>
</head>

<body>
  <!-- 
    常规的网页制作:
    先书写HTML -> 浏览器转换成 DOM元素 -> 显示在浏览器上
    -- 合理: HTML相当于语法糖, 容易写容易读

    但是: 大神们认为让浏览器 解析HTML代码转换成DOM元素 -- 浪费系统资源;   不如放弃HTML, 直接用JS来创建DOM元素 -- 追求极致的性能

    目前 WEB的第二大框架: React 就是采用此方式
   -->
  <div id="box"></div>

  <script>
    // 新建一个button

    // create创建 Element元素
    const btn = document.createElement('button')
    btn.innerHTML = '点我'
    btn.id = 'b1'
    btn.className = 'danger'

    console.log(btn);

    const box = document.getElementById('box')
    // 添加到 box 的子元素
    // append:新增/添加   child:子元素
    box.appendChild(btn) // 向box元素中,添加子元素

    // 字符串 -> 被浏览器解析成DOM元素 -> 再展示到页面上
    // box.innerHTML = '<button>啦啦啦</button>'

    // a = 6;
    // a = 10;
  </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>
</head>

<body>
  <div id="box"></div>

  <script>
    const data = ['铭铭', '亮亮', '楠楠', '小新', '涛涛']

    // 用 forEach 遍历 data, 制作成 DOM元素 (button) 类型
    // 添加到 box 的子元素里
    data.forEach(v => {
      // 常规: 字符串书写HTML代码, 需要浏览器解析成DOM元素
      // box.innerHTML += `<button>${v}</button>`

      // 高端: 抛弃HTML语法糖, 采用纯DOM
      const btn = document.createElement('button')
      btn.innerHTML = v
      // 添加到 box的子元素
      box.appendChild(btn)
    })

    // 问题: 目前的添加方式, 1个1个挨个往里加
    // 类似于: 家乐买了10个雪糕, 要放冰箱里, 问分几步?
    // 正常: 3步   开门 -> 一起放进去 -> 关门
    // 现在: 开门->放1个->关门 : 一次循环,  我们做了5次
  </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>
</head>

<body>
  <div id="box"></div>

  <script>
    const data = ['铭铭', '亮亮', '楠楠', '小新', '涛涛']
    // 之前: 制作一个放一次, 制作一个放一次...
    // 现在: 把制作好的DOM元素, 先放在一个虚拟容器里, 一起放到页面

    // create创建 Document文档 Fragment片段
    // 一个虚拟的容器, 用来放多个DOM元素
    const frag = document.createDocumentFragment()

    data.forEach(v => {
      const btn = document.createElement('button')
      btn.innerHTML = v
      // 把生成的DOM 先放在 虚拟的 文档片段里
      frag.appendChild(btn) // 类似 雪糕放到塑料袋里
    })
    // box: 相当于冰箱, 把所有东西 一起放进去
    box.appendChild(frag)

    // box:冰箱
    // frag: 塑料袋
    // 按钮: 雪糕

    // 以前: 雪糕 1个放冰箱 关门;  再开再放1个关门....
    // 现在: 先把雪糕放塑料袋, 然后 打开冰箱放进去:  省电
  </script>

  <!-- 
    此部分: 属于 造火箭的技术 -> 给开发框架 年薪40W .. 用的
    但是: 面试可能会问到 

    面试官的考察点: 上进心 -- 程序员的发展潜力
   -->
</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>
</head>

<body>
  <a href="http://www.tmooc.cn">Go Tmooc</a>
  <a href="">xxx</a>

  <script>
    // 用途: 主要是团队合作
    // 例如 家乐(JS) 和 马(HTML) 组队
    // 家乐开发JS, 需要给 a 标签添加个性化的 onclick 事件
    // 佩奇-不知道不应该写 href: <a href="">xxx</a>
    // 防御: 在JS中阻止默认事件, 放置 href 产生的刷新效果

    const a = document.querySelector('a')
    a.onclick = function (e) {
      // prevent阻止 Default默认
      e.preventDefault()

      // 超链接 带有 href: 点击后默认会进行跳转操作
      alert('a被点击了')
    }
  </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>
</head>

<body>
  <!-- 事件监听器: 团队合作, 多个人向同一个按钮添加多个事件 -->
  <button>我是按钮</button>

  <script>
    const btn = document.querySelector('button')
    // 问题: onclick 是个属性, 同时只能赋1个值
    btn.onclick = function () {
      alert("家乐是最棒的!")
    }

    btn.onclick = function () {
      alert("佩奇才是最棒的!")
    }

    // 事件监听器: 可以为1个事件 添加多个方法
    // add添加 Event事件 Listener监听器
    // 参数1: 事件名 -- 系统规定, 注意没有 on 开头
    btn.addEventListener('click', function () {
      alert('111111')
    })

    btn.addEventListener('click', function () {
      alert(22222)
    })
  </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 {
      width: 500px;
      height: 500px;
      background-color: #999;
      user-select: none;
      position: relative;
    }

    #box>span {
      position: absolute;
      display: inline-block;
      width: 26px;
      text-align: center;
      line-height: 26px;
      border-radius: 50%;
      border: 3px solid white;
      color: white;
      background-color: blue;
    }
  </style>
</head>

<body>
  <!-- 
    思路:
    1. 点击时, 创建一个元素 添加到页面上
    2. 通过事件参数, 获取 点击的坐标
    3. 设置给创建的元素, 显示在对应位置
   -->
  <div id="box"></div>

  <script>
    let num = 1

    box.onclick = function (e) {
      // 仅限 事件触发的当事人 target, 是box 的场景 才添加
      if (e.target !== this) return

      console.log(e) //展开查看, 猜一猜哪个是坐标
      // x,y: 点击位置距离 浏览器内容的左上角
      // offsetX, offsetY: 点击位置距离当前元素的左上角
      // screenX, screenY: 距离屏幕的左上角
      const span = document.createElement('span')
      span.innerHTML = num++ // 先赋值, 再+1
      const { offsetX, offsetY } = e
      // 默认是左上角, 需要移动到中间, 所以-13  1半的宽
      span.style.top = offsetY - 13 + 'px'
      span.style.left = offsetX - 13 + 'px'

      this.appendChild(span)
    }
  </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>div {
      padding: 10px;
      border-radius: 10px;
      background-color: gray;
      margin-bottom: 10px;
      width: 300px;
    }

    #xx {
      right: 0;
      position: fixed;
      top: 0;
      width: 100%;
      height: 100px;
      background-color: purple;
    }

    /* .hide {
      display: none;
    } */
  </style>
</head>

<body>
  <!-- 监听页面的滚动距离, 切换内容的显示与否 -->
  <div id="box"></div>
  <!-- diplay:'' -->
  <div id="xx" style="display: none"></div>

  <script>
    for (let i = 0; i < 1000; i++) {
      const div = document.createElement('div')
      div.innerHTML = i
      box.appendChild(div)
    }

    // window提供的, 监听窗口的滚动
    window.onscroll = function () {
      // console.log('onscroll');
      // 获取滚动的距离: 由于兼容性问题, 提供两种读取方式, 在不同浏览器上不一定哪个好用.  y的值就是其中 正常读取的值

      // document.documentElement.scrollTop: 获取滚动的距离
      // document.body.scrollTop: 获取滚动的距离

      const y = document.documentElement.scrollTop || document.body.scrollTop

      // 设定: 至少有一个人会答应, 不一定是谁
      // 例如: 家乐的媳妇 = 迪丽热巴答应不 || 马尔扎哈答应不
      // 所以: 家乐的媳妇是 后方表达式中 首个 为真的


      console.log('y:', y);

      // 如果 y > 4000 像素  就显示 div#xx; 否则就隐藏
      // display="none" 代表隐藏
      // display="" 代表不隐藏
      xx.style.display = y > 4000 ? '' : 'none'
      // if (y > 4000) {
      //   xx.classList.remove('hide')
      // } else {
      //   xx.classList.add('hide')
      // }
    }

    // 逻辑或 表达式的值: 是从左到右 第一个真值, 如果没有则是最后一个
    var a = null || 0 || '' || 11
    console.log(a);

    var b = null || 0 || '' || false || undefined
    console.log(b)
  </script>
</body>

</html>

回顾

  • 标签内容

    • innerHTML: 读取内容中的 html + 文本

    • innerText: 读取内容中的 文本

    • 注意: 如果标签内容只有文本, 则两种方式读取结果一样

  • 数组转HTML显示到页面的方式

    • 利用 map 方法映射数组为 HTML代码

    • 利用数组的 join 方法拼接成字符串

    • 利用 innerHTML 设置给元素

  • 冒泡机制

    • 当事件触发时, 会传递给父元素, 触发其相同的事件

    • 阻止冒泡: e.stopPropagation()

    • 事件委托: 通过父元素来帮子元素实现事件, 适合动态新增的子元素

  • 手动创建DOM元素 -- 获得极致的性能 重要的理念

    • 不写HTML代码, 而是直接用JS代码来创建DOM元素

  • 阻止默认事件: e.preventDefault()

  • 事件监听器: addEventListener

    • 可以为一个事件 重复绑定多个方法

  • 鼠标事件: 主要是 几个坐标值

  • 滚动监听: onscroll 监听滚动的距离, 然后做事

    • 总体思路: 监听滚动距离 当达到一个临界值, 把元素 显示/隐藏

扩展视频

www.xin88.top 提供的网盘里, 有进阶视频, 查看 防抖和节流

DOM05

复习

DOM的核心操作: 找到元素 -> 操作其属性

  • 找到元素的方式

    • 固定: head, body, documentElement

    • 关系: 儿子们, 第一个孩子, 下一个兄弟, 父...

    • 特征: id, 标签名, class, name

    • css选择器: querySelectorquerySelectorAll

  • 属性的操作

    • 标签的内容

      • innerHTML: 获取HTML+文本

      • innerText: 获取文本

      • 注意: 如果标签中只有文本内容, 则两种读法结果相同

    • 数组转HTML:

      • 数组中存储的是数据, 使用map映射成HTML

      • 利用 join() 拼接成字符串

      • 利用 innerHTML 添加到元素中

    • 冒泡: 事件在元素上触发时, 会传递给其父元素, 触发相同的事件

      • 利用事件参数 :stopPropagation 来阻止冒泡

      • 使用场景: 动态添加的子元素 的事件监听, 适合给父元素添加

        • 事件委托: 子元素的事件 委托给父元素处理

    • 追求极致的性能: 通过JS创建DOM元素

      • 普通: 先书写HTML -> 浏览器帮助转换成DOM -> 显示到页面

      • 现在: JS创建DOM的代码 -> 显示到页面

    • 阻止默认: preventDefault

    • 事件监听器: 在团队合作项目中非常好用

      • addEventListener: 可以为一个事件 添加多个方法

    • 鼠标事件: 记住几组坐标值的用法, 坐标系是什么

    • 滚动监听:

      • onScroll 事件: 来自window. 用来监听整个页面的滚动

      • 通常搭配滚动偏移量, 来决定一些元素的显示与否

        • 因为兼容性的问题, 不同浏览器, 读取滚动偏移量scrollTop 方式不同 有的是从 body 读取, 有的是从documentElement读取

        • const y = document.body.scrollTop || document.documentElement.scrollTop

        • 逻辑或表达式的值: 从左到右第一个真值, 如果没有真值,则使用最后一个

          const a = null || false || 0 || 11 || true   //a = 11

有时间多回顾 CSS: class 和 style 是两个体系

  • class: 优先级比style低, 具体看 选择器的权重

  • style: 最高的优先级

如果style的属性 和 class 的属性重复, 则style生效

style="display: none": 隐藏

元素.style.display='': 空字符串代表这个style没有设置, 则class生效

属性读取

<!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>
</head>
​
<body>
  <a href="http://www.tmooc.cn" id="a1" class="danger" data-xx="11" data-yy="22">Go Tmooc</a>
​
  <script>
    // DOM元素的属性分: 系统 和 自定义 data-
    const a1 = document.getElementById('a1')
    console.dir(a1)
​
    // 读取属性的 旧写法
    // get获取 Attribute属性
    console.log(a1.getAttribute('id'))
    console.log(a1.getAttribute('href'))
    // 修改:  set设置
    a1.setAttribute('href', 'http://www.baidu.com')
    // 判断元素是否设置了 某个属性
    // has: 有
    console.log(a1.hasAttribute('id')) //true
    console.log(a1.hasAttribute('target')) //false
​
    // 自定义属性
    console.log(a1.getAttribute('data-xx'))
​
​
    //读取系统属性
    console.log(a1.id)
    console.log(a1.className)
    // 自定义属性 dataset
    console.log(a1.dataset.xx)
    console.log(a1.dataset.yy)
  </script>
</body>
​
</html>

BOM

Browser Object Model: 浏览器对象模型

一些用于操作浏览器的API

<!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>
</head>
​
<body>
  <!-- replace: 替换 -->
  <button onclick="location.replace(`http://www.baidu.com`)">切换到百度</button>
  <button id="b3">3秒后跳转</button>
​
  <script>
    // 手动为当前路径结尾添加  ?name=家乐&age=19
    // URLSearchParams: 专门转化 URL的传参
    const params = new URLSearchParams(location.search)
    console.log(params.get('name')) // 读取 name 属性的值
​
    b3.onclick = function () {
      setTimeout(() => {
        location.replace('http://www.tmooc.cn')
      }, 3000);
    }
​
    console.log(location);
​
    // 需求1: 每隔2s 刷新一次页面
    setInterval(() => {
      // location.reload()
    }, 2000);
  </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>open</title>
</head>
​
<body>
  <!-- 编程方式开启新的网页:open -->
  <a href="http://www.baidu.com" target="_blank">百度一下</a>
​
  <!-- 常见于 广告 -->
  <button id="b1">3秒后开启新页面</button>
​
  <script>
    b1.onclick = function () {
      setTimeout(() => {
        open('http://www.tmooc.cn')
        // JS高级第一天: 在全局中直接用的属性, 存储在 window 里
      }, 3000);
    }
  </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>
</head>
​
<body>
  <a href="./05.历史信息.html">历史</a>
​
  <script>
    console.log(navigator);
    // 读取到 浏览器所在的系统信息, 浏览器的插件信息等...
    // 然后可以判断 进而提供个性化的一些操作
  </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>
</head>
​
<body>
  <!-- 利用 history 的 go 方法 -->
  <!-- go(n): n<0代表后退  n>0代表前进   n=0 代表刷新 -->
  <!-- 如下: n是几,就是几页-->
  <button onclick="history.go(-1)">上一页</button>
  <button onclick="history.go(1)">下一页</button>
  <button onclick="history.go(0)">刷新</button>
  <hr>
  <a href="./04.浏览器信息.html">浏览器信息</a>
​
  <script>
    console.log(history);
  </script>
</body>
​
</html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值