DOM02

DOM02

复习

HTML代码 会先转换成 DOM对象, 然后显示在浏览器上

  • 浏览器实际显示的是 DOM对象的内容

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2d83Dvw5-1645336739306)(C:\Users\jiyx\AppData\Roaming\Typora\typora-user-images\image-20220106090217948.png)]

DOM: document object model 文档对象模型

本质是 window.document 属性, 利用此属性可以操作浏览器中的内容显示

DOM树: 对DOM对象结构的一种称呼, 结构像树形结构

  • 父元素
  • 兄弟元素

DOM操作核心就两种:

  • 查找要操作的元素:
    • 固定元素: head, body, documentElement - html
    • 按照与已知元素的关系查找
      • 第一个孩子: firstElementChild
      • 最后一个孩子: lastElementChild
      • 所有孩子: children
      • 上一个兄弟: prevElementSibling
      • 下一个兄弟: nextElementSibling
      • 父: parentElement
    • 按照特征查找
      • id: getElementById
        • id是唯一标识, 此方法的返回值 是元素本身
      • class: getElementsByClassName
        • class可以同名多个, 结果是 伪数组, 用for…of遍历
      • 标签: getElementsByTagName
      • name: getElementsByName
    • 利用css选择器查找
      • 查单个: querySelector
        • 返回值 是元素本身
      • 查多个: querySelectorAll
        • 返回值是伪数组类型, 但是原型中有借用的 forEach方法可以遍历
  • 对元素属性进行操作
    • style: 内联样式
    • class
      • className: 简单的修改 class的值, 是字符串
      • classList: 优雅
        • add: 添加
        • remove: 删除
        • toggle: 切换
    • 事件: 都是 on 开头
      • onclick: 点击
      • onmouseover: 鼠标悬浮

作业1

<!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>
      .menu {
        background-color: #f2f5f6;
        padding: 10px;
        user-select: none;
      }
      .menu > span {
        width: 100px;
        height: 40px;
        color: #777;
        text-align: center;
        line-height: 40px;
        display: inline-block;
        background-color: white;
        border-radius: 20px;
        margin-right: 5px;
        border: 1px solid #eee;
      }
      .menu > .cur {
        background-color: #ff5d23;
        color: white;
        border-color: #ff5d23;
      }
      /* not:排除 */
      .menu > span:not(.cur):hover {
        border-color: #ff5d23;
        color: #ff5d23;
      }
    </style>
  </head>
  <body>
    <div class="menu">
      <span class="cur">推荐分类</span>
      <span>网游竞技</span>
      <span>单机热游</span>
      <span>手游休闲</span>
      <span>娱乐天地</span>
      <span>颜值</span>
    </div>

    <script>
      // 如果不写bind, qsa调用时, this指向window
      // 简化
      const qsa = document.querySelectorAll.bind(document)
      // doc 回车 .qus 回车 .b 回车 (doc 回车
      const qs = document.querySelector.bind(document)

      // 查找 class='menu' 下的所有span标签
      qsa('.menu span').forEach(value => {
        value.onclick = function () {
          qs('.menu .cur').classList.remove('cur')
          this.classList.add('cur')
        }
      })
    </script>
  </body>
</html>

作业2

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .tab {
        user-select: none;
      }
      .tab > span {
        padding: 8px;
        background-color: #eee;
        float: left;
        border: 1px solid #aaa;
      }
      .tab > .cur {
        background-color: white;
        border-bottom-color: white;
      }
    </style>
  </head>
  <body>
    <div class="tab">
      <span class="cur">今日点数</span>
      <span>本周点数</span>
      <span>贵宾(746)</span>
      <span>钻粉(0)</span>
    </div>

    <script>
      let tabs = document.querySelectorAll('.tab>span')

      tabs.forEach(tab => {
        tab.onclick = function () {
          document.querySelector('.tab>.cur').classList.remove('cur')
          this.classList.add('cur')
        }
      })
    </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>Document</title>
    <style>
      .btn {
        width: 300px;
        display: inline-block;
        padding: 6px 0;
        text-align: center;
        color: white;
        background-color: #72b134;
        border-radius: 4px;
        user-select: none;
        transition: 0.25s;
      }
      .btn:not(.disabled):hover {
        opacity: 0.8;
      }
      .btn.disabled {
        background-color: #bbb;
      }
    </style>
  </head>
  <body>
    <div>
      <!-- label: 子元素中的文本 在点击后, 也能触发勾选 -->
      <label>
        <input type="checkbox" />
        <span>我已阅读并同意用户注册协议</span>
      </label>
      <div class="btn disabled">提交注册</div>
    </div>

    <script>
      // 获取 checkbox 元素
      let chb = document.getElementsByTagName('input')[0]
      // 监听 变化:  change:变化   点击->触发了变化
      chb.onchange = function () {
          console.dir(this); // 查看checked属性
        //checked 属性: 代表勾选框的勾选状态
        console.dir(this.checked)
        // 勾选框的父元素的下方的元素
        const btn = this.parentElement.nextElementSibling
        // 勾选 ? 真-移除不可用 : 假-添加不可用
        this.checked
          ? btn.classList.remove('disabled')
          : btn.classList.add('disabled')
      }
      // 根据勾选状态, 切换 按钮的disabled 样式
    </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>
  </head>
  <body>
    <div>
      <input type="text" />
    </div>

    <script>
      const inp = document.getElementsByTagName('input')[0]

      //获的焦点: 点击后光标闪烁时
      inp.onfocus = function () {
        console.log('获得焦点')
      }
      // 失去焦点
      inp.onblur = function () {
        console.log('失去焦点')
      }
      // 内容变更事件: change
      // 触发: 修改其内容->失去焦点后 触发
      inp.onchange = function () {
        console.log('内容变更')
      }
      // 内容变更的实时监听:
      inp.oninput = function () {
        // 输入框的 value属性 保存输入框的值
        console.log(this.value)
      }
      // 键盘事件有3个:  按下,抬起,整个过程
      // keyup: 按键抬起
      inp.onkeyup = function (e) {
        // 所有通过事件触发的函数, 都会接受一个默认参数
        // 形参名随意, 但是 event 是事件的意思, 习惯叫event, 偷懒写: e
        // console.log(arguments)
        console.log('e:', e)
        console.log('按键抬起')
        // 回车: keyCode -- 13
        if (e.keyCode == 13) {
          console.log('回车操作')
        }
      }
    </script>
  </body>
</html>

手机号验证(XXX)

<!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>
      .err {
        color: red;
      }
      .hidden {
        display: none;
      }
    </style>
  </head>
  <body>
    <div>
      <div>
        <span>手机号</span>
        <input type="text" />
      </div>
      <div class="err hidden">手机号格式不正确</div>
    </div>

    <script>
      const inp = document.getElementsByTagName('input')[0]
      // blur: 失去焦点
      inp.onblur = function () {
        // this.value: 输入框的值
        const reg_phone = /^1[3-9]\d{9}$/
        // 判断手机号格式是否合法, 决定 hidden样式的去留
        const err = this.parentElement.nextElementSibling
        if (reg_phone.test(this.value)) {
          err.classList.add('hidden')
        } else {
          err.classList.remove('hidden')
        }
      }

      // 当输入框获取焦点时: onfocus,  隐藏 err 提示
      // 对象.属性名:  这就是读操作,  this.value 就是读
      inp.onfocus = function () {
        this.parentElement.nextElementSibling.classList.add('hidden')
      }
    </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>
      .pwd > div:last-child {
        display: inline-block;
        background-color: rgba(0, 0, 0, 0.5);
        padding: 9px;
        border-radius: 4px;
        margin-top: 10px;
        color: white;
      }
      .err {
        color: red;
      }
      .hidden {
        display: none !important;
      }
    </style>
  </head>
  <body>
    <div class="pwd">
      <div>
        <span>密码:</span>
        <input type="password" />
      </div>
      <div class="hidden">
        <div>长度为8~14个字符</div>
        <div>字母/数字以及标点符号至少包含2种</div>
        <div>不允许有空格,中文</div>
      </div>
    </div>

    <script>
      let inp = document.getElementsByTagName('input')[0]
      // 1. 输入框获得焦点时 - 把提示框的 hidden样式删除
      inp.onfocus = function () {
        this.parentElement.nextElementSibling.classList.remove('hidden')
      }

      // 2. 输入框失去焦点时 - 把提示框的 hidden样式添加
      inp.onblur = function () {
        document.querySelector('.pwd>div:last-child').classList.add('hidden')
      }
      // 3. 监听输入框的实时变化: oninput
      inp.oninput = function () {
        // 数组解构: const [a,b,c] = [11,22,33]
        const [c1, c2, c3] = this.parentElement.nextElementSibling.children
        //1.长度
        const len = this.value.length
        if (len >= 8 && len <= 14) {
          c1.classList.remove('err')
        } else {
          c1.classList.add('err')
        }
        // 2. 不能有中文/空格
        // \s:空白字符   |是或    [...] 是匹配中文
        if (this.value.match(/\s|[\u4e00-\u9fa5]/)) {
          c3.classList.add('err')
        } else {
          c3.classList.remove('err')
        }
        // 2. 数字 字母 标点符号: 至少有2种
        // 储备: 数学运算中 true->1  false->0
        const hasNum = this.value.match(/\d/)
        const hasLetter = this.value.match(/[a-z]/i)
        // [] 代表其中元素任意一个
        const hasP = this.value.match(/[!@#$%^&*,.';"]/)
        console.log(hasP)
        // match的返回值是 数组类型 或 null
        // 此处需要用 Boolean() 强转布尔类型
        const res = Boolean(hasNum) + Boolean(hasLetter) + Boolean(hasP)
        res >= 2 ? c2.classList.remove('err') : c2.classList.add('err')
      }
     
    </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>
  </head>
  <body>
    <a href="http://tmooc.cn" id="a1" title="Tmooc">Go To Tmooc</a>

    <script>
      const a = document.getElementsByTagName('a')[0]
      console.dir(a) //查看 其中的各种属性

      // 标签所有的系统属性 都可以直接读取
      console.log(a.id)
      console.log(a.href)
      console.log(a.title)
      // 修改
      a.href = 'http://www.baidu.com'
      a.title = '百度一下'

      // 早期版本中, 提供函数方式来读取属性/修改属性
      // get获取 Attribute属性  : 现在用的少
      console.log(a.getAttribute('title'))
      //改:  set:设置
      a.setAttribute('title', 'Tmooc 我又来了')

      // 判断是否存在某个属性:
      console.log(a.hasAttribute('target')) //true代表有
      // 新语法中, 不存在的属性,默认值是空字符串
      console.log(a.target == '')
    </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>
  </head>
  <body>
    <!-- 标签的属性分两种: 系统属性 和 自定义属性 -->
    <!-- 自定义属性: 格式要求  data-属性名 -->
    <div id="d1" data-a="AA" data-b="BB">Hello</div>

    <script>
      const d1 = document.getElementById('d1')
      // dataset 属性: 固定的 用于存储自定义属性
      console.dir(d1) // 查看 dataset 属性
      // 新语法
      console.log(d1.dataset.a)
      console.log(d1.dataset.b)
      // 旧语法
      console.log(d1.getAttribute('data-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>Document</title>
    <style>
      .box > img {
        width: 500px;
      }
      .box > div > img {
        width: 121px;
        /* 边框盒子: 宽度=边框+内边距+内容 */
        box-sizing: border-box;
      }
      .box > div > img:hover,
      .box > div > img.cur {
        border: 2px solid red;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <img src="./images/1-l.jpg" alt="" />
      <div>
        <!-- 为每一个小图增加一个自定义属性, 保存对应的大图的名字 -->
        <img data-big="1-l.jpg" class="cur" src="./images/1.jpg" alt="" />
        <img data-big="2-l.jpg" src="./images/2.jpg" alt="" />
        <img data-big="3-l.jpg" src="./images/3.jpg" alt="" />
        <img data-big="4-l.jpg" src="./images/4.jpg" alt="" />
      </div>
    </div>

    <script>
      // 任务1: 鼠标悬浮小图, 切换 cur 这个class 给悬浮项
      // 事件: onmouseover
      const imgs = document.querySelectorAll('.box>div>img')
      /*
      	1. 查询出所有小图
      	2. 遍历小图,挨个添加mouseover事件
      	3. 事件出发后,找到当前cur,删除其样式,为当前项添加cur
      */
      imgs.forEach(img => {
        img.onmouseover = function () {
          document.querySelector('.box .cur').classList.remove('cur')
          this.classList.add('cur')
          // 读取自定义的 data-big 属性
          console.log(this.dataset.big)
          //const { big } = this.dataset //对象解构
          const big = this.dataset.big;
          const big_img = document.querySelector('.box>img')
          // 拼接出 全路径
          big_img.src = './images/' + big
        }
      })
    </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>
      .tab {
        display: inline-block;
        user-select: none;
      }
      .tab > div:first-child {
        border-bottom: 2px solid #e01222;
        display: flex;
      }
      .tab > div:first-child > span {
        font-weight: bold;
        padding: 10px;
      }
      .tab > div:first-child > span.cur {
        background-color: #e01222;
        color: white;
      }

      .tab > div:last-child > div {
        height: 200px;
        display: none;
      }
      .tab > div:last-child > div.show {
        display: block;
      }
      .tab #tab1 {
        background-color: #e01222;
      }
      .tab #tab2 {
        background-color: deeppink;
      }
      .tab #tab3 {
        background-color: deepskyblue;
      }
      .tab #tab4 {
        background-color: darkred;
      }
    </style>
  </head>
  <body>
    <div class="tab">
      <div>
        <span data-id="tab1" class="cur">京东秒杀</span>
        <span data-id="tab2">每日特价</span>
        <span data-id="tab3">品牌秒杀</span>
        <span data-id="tab4">品类秒杀</span>
      </div>
      <div>
        <div id="tab1" class="show">京东秒杀...</div>
        <div id="tab2">今日特价...</div>
        <div id="tab3">品牌秒杀...</div>
        <div id="tab4">品类秒杀...</div>
      </div>
    </div>

    <script>
      const titles = document.querySelectorAll('.tab>div:first-child>span')

      titles.forEach(title => {
        title.onclick = function () {
          document.querySelector('.tab .cur').classList.remove('cur')
          this.classList.add('cur')
          // 移除之前 show
          document.querySelector('.tab .show').classList.remove('show')
          // 从自定义属性 dataset 中解构出 id
          //const { id } = this.dataset
            const id = this.dataset.id;
          // 通过id查找到对应的元素
          document.getElementById(id).classList.add('show')
        }
      })
    </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>
      #red {
        background-color: red;
        width: 300px;
        height: 300px;
      }
      #blue {
        background-color: blue;
        width: 200px;
        height: 200px;
      }
      /* 多光标模式: alt+左键 , 按ESC退出此模式*/
      #green {
        background-color: green;
        width: 100px;
        height: 100px;
      }
    </style>
  </head>
  <body>
    <!-- 事件冒泡机制: -->
    <!-- 子元素触发一个事件后, 会通知给其所有的祖先元素, 这是浏览器自带的效果, 称为冒泡机制 -->
    <!-- 类似: 泽权 -> 暴打了 高达 -> 高达会告诉他爸被打了.. -> 告诉他爷爷被打了 -> 祖爷爷自己被打了.. -->

    <div id="red">
      <div id="blue">
        <div id="green"></div>
      </div>
    </div>

    <script>
      // 绿(子) 蓝(父) 红(祖父)
      // 冒泡机制: 子元素发生事件 -> 会通知所有祖先元素
      // id 属性可以直接用  id='red'
      red.onclick = function (e) {
        // 参数e: 保存了事件有关的各种信息
        // 其中 的target属性, 代表具体是哪个元素触发的事件
        console.log('target:', e.target)
        console.log('red侦测到点击事件')
      }
      blue.onclick = function () {
        console.log('blue侦测到点击事件')
      }
      green.onclick = function () {
        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>Document</title>
    <style>
      .indicator {
        padding: 10px;
        background-color: lightgray;
        user-select: none;
      }
      .indicator > span {
        display: inline-block;
        width: 16px;
        height: 16px;
        background-color: white;
        transition: 0.25s;
      }
      .indicator > .cur {
        background-color: aqua;
        border-radius: 50%;
      }
    </style>
  </head>
  <body>
    <!-- 冒泡机制的应用场景: 事件委托 -->
    <!-- 
      工作时 -- 报销流程非常繁琐:
      方式1: 教会每个工作人员报销流程
      方式2: 1个负责人会报销流程: 其他人报销让其帮忙即可
      ------- 这个负责人就是委托人, 代理人..

      在代码中:
      以前: 遍历元素 挨个添加事件
      现在: 让父元素来处理子元素的事件, 父元素就是 代理人
     -->
    <div class="indicator">
      <span class="cur"></span>
      <span></span>
      <span></span>
      <span></span>
    </div>

    <script>
      // 根据冒泡机制: 任意子元素悬浮事件, 都会触发父元素的相同事件
      const ind = document.getElementsByClassName('indicator')[0]

      ind.onmouseover = function (e) {
        // 注意事项: 所有子元素+当前元素自身都能触发事件, 所以一定要用 if判断进行过滤, 找到你想要的
        // target: 触发事件的元素
          // console.log('target:', e.target)
        if (e.target.localName == 'span') {
          console.log('target:', e.target)
          console.dir(e.target)
          document.querySelector('.cur').classList.remove('cur')
          //为当前项添加 cur 样式
          // this: 指向函数运行时所在的对象, 此处是父元素
          // target: 才是触发事件的元素
          e.target.classList.add('cur')
        }
      }
    </script>
  </body>
</html>

练习 - 分页

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QceLgdZV-1645336739310)(DOM02.assets/image-20220106180557698.png)]

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
        .pages {
          background-color: lightgray;
          padding: 5px;
          width: 400px;
          text-align: center;
          user-select: none;
        }
        .pages > span {
          display: inline-block;
          width: 30px;
          height: 30px;
          line-height: 30px;
          background-color: white;
          color: deepskyblue;
          border-radius: 4px;
        }
        .pages > span:hover,
        .pages > span.cur {
          color: white;
          background-color: deepskyblue;
        }
      </style>
  </head>
  <body>
    <div class="pages">
      <span class="cur">1</span>
      <span>2</span>
      <span>3</span>
      <span>4</span>
      <span>5</span>
    </div>
      
      <script>
          //要求:用委托方式实现
          /*
          	1. 先添加基本的css样式
          	2. 为pages添加点击事件
          	3. 利用事件的target,用if过滤出span元素出发
          	4. 移除cur 样式
          	5. 为当前点击元素 添加cur样式
          */
          const page = document.getElementsByClassName('pages')[0];
          console.log(page);
          page.onclick=function(e){
              if(e.target.localName=='span'){
                  document.querySelector('.cur').classList.remove('cur')
                  e.target.classList.add('cur');
              }

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

小总结

当为多个子元素添加事件时, 有两种方式

  1. 找到所有的子元素, 进行遍历, 挨个添加事件
  2. 利用冒泡机制, 只给父元素添加事件, 让父元素来监听子元素触发的事件然后做事 – 委托

晚上作业

把今天的各种练习, 尝试用委托方式来实现

明天: 购物车的制作, 操作标签内容之类…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值