DOM03

本文档介绍了DOM的概念及其在浏览器中的作用,详细讲解了如何通过JavaScript操作DOM来修改网页内容,包括查找元素、操作元素样式、读取和设置属性、事件委托等。此外,还提供了多个实例,如计数器、数组转HTML、购物车功能等,展示了DOM在实际应用中的使用技巧。
摘要由CSDN通过智能技术生成

DOM03

复习

DOM: Document Object Model 文档对象模型

HTML文本代码 -> 转化成DOM -> 显示在浏览器上

浏览器展示的是DOM, 通过操作DOM 就可以实时修改浏览器的效果

查找元素:

  • 固定元素读取
    • document.head
    • document.body
    • document.documentElement: 整个html
  • 按照与已知元素的关系
    • 父: parentElement
    • 子:
      • 第一个: firstElementChild
      • 最后一个: lastElementChild
      • 所有孩子: children 利用下标读取具体的某个
    • 兄弟
      • 上一个: previousElementSibling
      • 下一个: nextElementSibling
  • 按照特征读取
    • id: getElementById – 结果是元素本身
    • class: getElementsByClassName – 结果是伪数组-遍历/下标取值
    • name: getElementsByName – 结果是伪数组-遍历/下标取值
    • tag: getElementsByTagName – 结果是伪数组-遍历/下标取值
  • 利用 css 选择器读取
    • querySelector(css选择器): 读取单个元素
    • querySelectorAll: 读取多个元素, 原型中有 forEach 方法可用

操作元素:

  • style属性: 操作内联样式

  • class

    • className: 字符串的值, 简单粗暴的修改 class的值
    • classList: 优雅的修改
      • add: 添加
      • remove: 移除
      • toggle: 切换
  • 系统属性读取

      • 元素.属性名
      • 元素.属性名 = 值
      • 元素.属性名==''
      • 元素.getAttribute(属性名)
      • 元素.setAttribute(属性名, 值)
      • 元素.hasAttribute(属性名)
  • 自定义属性

    • 要求格式: data-属性名=值
    • 读取
      • 新: 元素.dataset.属性名, 自定义属性固定存储在dataset中
      • 旧: 元素.getAttribute('data-xxx')
  • 冒泡机制

    • 子元素触发事件之后, 会通过所有的祖先元素, 触发相同的事件, 其中事件参数的 e.target 代表了事件具体是谁触发的
    • 事件委托 : 让父元素代为管理 子元素的事件
  • 常见事件

    • click: 点击
    • mouseover: 鼠标悬浮
    • focus: 获得焦点
    • blur: 失去焦点
    • change: 发生变化
      • 输入框的值: value 属性读取
      • 勾选框的值: checked 属性读取
    • input: 输入框值的实时变化监听
    • keyup: 按键抬起, 利用 e.keyCode == 13 代表回车

本阶段的各种资源

https://pan.baidu.com/s/10oVRMBaEDL9uQSB1Jrrc3w
提取码:6666

双标签内容

<!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 id="box">
      <p>Hello</p>
      <b>World</b>
    </div>

    <script>
      const box = document.getElementById('box')
      console.dir(box) //查看其中的 innerHTML 和 innerText
      // innerHTML: 读取标签内容中的 所有HTML代码
      console.log('html:', box.innerHTML)
      // innerText: 读取标签内容中的 文本部分, 不含HTML代码
      console.log('text:', box.innerText)

      // 修改: 1.替换标签原有内容   2.HTML标签被解析
      box.innerHTML = '<h1>打亮亮</h1>'
      // 累加:
      box.innerHTML += '<h1>打高达</h1>'

      // 差异: 把内容当做文本进行展示, HTML标签不解析
      box.innerText = '<h1>打亮亮</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>
    <button>1</button>

    <script>
        /*
        	1. 找到按钮
        	2. 加点击事件
        	3. 获取按钮上的文字
        	4. 给文字 +1
        	5.赋值回按钮上, 替换之前的值
        */
      // const:常量, 不可修改, 安全
      // let: 可修改, 适合值需要修改的场景

      // 点击按钮, 让上方的文字+1
      const btn = document.getElementsByTagName('button')[0]

      btn.onclick = function () {
        // this.innerHTML++
        // return
        let num = this.innerHTML //标签内容都是 字符串类型
        // num++ ; ++:自增,  转数字然后自身+1
        // 利用隐式转换, *1 把任意类型转成数字
        num = num * 1 + 1
        // 覆盖之前的值
        this.innerHTML = num
      }
    </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>
      <button disabled>-</button>
      <span>1</span>
      <button>+</button>
    </div>

    <script>
      // 思路1: 分别为 -按钮 和 +按钮添加事件
      const num = document.querySelector('span')
      const jian = num.previousElementSibling //上一个兄弟
      const jia = num.nextElementSibling //下一个兄弟

      jia.onclick = function () {
        num.innerHTML++
        // 减按钮的不可用变为假 -> 不不可用->可用
        jian.disabled = false
      }
      jian.onclick = function () {
        num.innerHTML--
        // 当 ==1 让不可用属性生效
        console.dir(this)
        // disabled: 不可用
        if (num.innerHTML == 1) this.disabled = true
        console.log(this.disabled)
        // 语法糖:  if(条件) {一行代码}    可以省略{}
      }

      // 思路2: 利用事件委托 给父元素添加事件监听
    </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 id="counter">
      <button disabled>-</button>
      <span>1</span>
      <button>+</button>
    </div>

    <script>
      // 事件委托: 依赖冒泡机制-子元素的事件就会传到给父元素
      const counter = document.getElementById('counter')
      counter.onclick = function (e) {
        // 事件委托: 必须通过target过滤出你需要的元素
        if (e.target.localName == 'button') {
          console.dir(e.target)
          const num = this.children[1]
          const jian = this.children[0]
          //const [jian, num] = this.children //数组解构

          // 根据按钮上的文本,判断出是什么按钮
          if (e.target.innerHTML == '+') {
            num.innerHTML++
            jian.disabled = false // 不 不可用 -> 可用
          }
          if (e.target.innerHTML == '-') {
            num.innerHTML--
            if (num.innerHTML == 1) jian.disabled = true
          }
        }
      }
    </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>
      .cell {
        border: 1px solid lightgray;
        width: 400px;
        display: flex;
        justify-content: space-between;
        padding: 10px;
        border-radius: 4px;
      }
    </style>
  </head>
  <body>
    <div class="cell">
      <span>¥99</span>
      <div>
        <button disabled>-</button>
        <span>1</span>
        <button>+</button>
      </div>
      <span>¥99</span>
    </div>

    <script>
      const [jian, num, jia] = document.querySelector('.cell>div').children
      // 实现+1
      jia.onclick = function () {
        num.innerHTML++
        jian.disabled = false
        updateSubtotal() //更新小计
      }
      // 实现-1
      jian.onclick = function () {
        num.innerHTML--
        if (num.innerHTML == 1) this.disabled = true
        updateSubtotal() //更新小计
      }

      // +1 和 -1 都需要: 获取单价 x 数量, 结果赋值给小计
      // 制作函数, 更新小计 -> 目的复用. +1 -1 都触发
      function updateSubtotal() {
        const [price, , subtotal] = document.querySelector('.cell').children
        // slice(i): 从字符串的序号i位置 截取
        console.log('price:', price.innerHTML.slice(1))
        const price_value = price.innerHTML.slice(1)
        const num_value = num.innerHTML
        subtotal.innerHTML = '¥' + price_value * num_value
      }
    </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>Document</title>
  </head>
  <body>
    <!-- 
      实际工作中, 数据都是通过网络接口请求的, 通常是数组类型
      我们需要把数组中的数据转化成HTML代码, 最终展现到页面上
     -->
    <div id="box"></div>

    <script>
      // 假数组  -- 以后学习网络请求ajax,再用真数组
      const names = ['高达', '海浪', '启航', '泽权']
      // 期望: 把每个元素放到 按钮标签里, 最后显示到页面上
      // 例如: '高达' -> '<button>高达</button>'
      // 数组高阶函数: map, 把数组的每个元素处理之后, 返回值形成新的数组
      const btns = names.map(value => {
        // ``:模板字符串, 特别适合 HTML代码的拼接
        return `<button>${value}</button>`
      })
      console.log('btns:', btns)
      // 数组的元素拼接到一起, 形成字符串用什么方法? join
      // join(','): 默认拼接时, 用逗号间隔
      console.log('join:', btns.join(''))

      // 放到 id='box' 的元素中
      const box = document.getElementById('box')
      // 一定要用 innerHTML, 才能解析文本中的 html标签
      box.innerHTML = btns.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>Document</title>
  </head>
  <body>
    <ul id="box"></ul>
    <script>
      const products = ['APPLE', 'OPPO', 'HUAWEI', 'XIAOMI']
      // 期望: 把每个元素放到 li 标签里, 然后显示到页面
      // 用map转化 -> 用innerHTML添加到 id=box 元素中
      const lis = products.map(value => `<li>${value}</li>`)
      box.innerHTML = lis.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>Document</title>
  </head>
  <body>
    <div id="box">
      <!-- 由于在模板字符串中书写HTML代码, 没有代码提示; 推荐如果HTML复杂, 就好在 HTML中先写好, 然后复制粘贴改一改 -->
      <!-- <div><a href="地址">标题</a></div> -->
    </div>

    <script>
      const news = [
        { title: '百度一下', url: 'http://www.baidu.com' },
        { title: 'TMOOC', url: 'http://tmooc.cn' },
        { title: '哔哩哔哩', url: 'http://www.bilibili.com' },
        { title: '斗鱼', url: 'http://www.douyu.com' },
      ]
      // 转换映射: el 是element缩写, 代表元素
      const news_el = news.map(value => {
        //先解构 再使用
        const { title, url } = value
        return `<div><a href="${url}">${title}</a></div>`
      })
      console.log(news_el)

      const box = document.getElementById('box')
      box.innerHTML = news_el.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>Document</title>
    <style>
      .cell {
        width: 400px;
        display: flex;
        justify-content: space-between;
        padding: 10px;
        border: 1px solid gray;
      }
    </style>
  </head>
  <body>
    <div id="box">
      <!-- <div class="cell">
        <div>姓名: xxx</div>
        <div>年龄: xxx</div>
        <div>手机号: xxx</div>
      </div> -->
    </div>

    <script>
      const emps = [
        { name: '亮亮1', age: 31, phone: '1878787777' },
        { name: '亮亮2', age: 30, phone: '1878787577' },
        { name: '亮亮3', age: 32, phone: '1878787477' },
        { name: '亮亮4', age: 34, phone: '1878227777' },
        { name: '亮亮5', age: 35, phone: '1878447777' },
      ]

      const emps_el = emps.map(value => {
        // 先写 const {} = value;  然后在补充{}的值, 有提示
        const { name, age, phone } = value
        return `<div class="cell">
        <div>姓名: ${name}</div>
        <div>年龄: ${age}</div>
        <div>手机号: ${phone}</div>
      </div>`
      })

      document.getElementById('box').innerHTML = emps_el.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>Document</title>
    <style>
      .cell {
        width: 500px;
        display: flex;
        justify-content: space-between;
        padding: 10px;
        border: 1px solid gray;
      }
      .cell:first-child {
        background-color: beige;
      }
    </style>
  </head>
  <body>
    <div id="box">
      <div class="cell">
        <span>序号</span>
        <span>名字</span>
        <span>单价</span>
        <span>数量</span>
        <span>小计</span>
      </div>
    </div>

    <script>
      const products = [
        { name: 'iPhone1', price: 4999, count: 4 },
        { name: 'iPhone2', price: 5999, count: 1 },
        { name: 'iPhone3', price: 6999, count: 7 },
        { name: 'iPhone4', price: 7999, count: 10 },
      ]

      const products_el = products.map((value, index) => {
        // ctrl+i: 弹出提示
        const { name, count, price } = value

        return `<div class="cell">
        <span>${index + 1}</span>
        <span>${name}</span>
        <span>¥${price}</span>
        <span>${count}</span>
        <span>¥${price * count}</span>
      </div>`
      })

      // 累加拼接:保留默认内容
      const box = document.getElementById('box')
      box.innerHTML += products_el.join('')
    </script>
  </body>
</html>

购物车 - 1.7pm 108分

<!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>
      table {
        border-collapse: collapse;
      }
      td {
        border: 1px solid gray;
        padding: 10px;
        text-align: center;
      }
    </style>
  </head>
  <body>
    <table>
      <thead>
        <tr>
          <td><input type="checkbox" />全选</td>
          <td>序号</td>
          <td>商品名</td>
          <td>单价</td>
          <td>数量</td>
          <td>小计</td>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>xxx</td>
          <td>xxx</td>
          <td>xxx</td>
          <td>
            <button>-</button>
            <span>xxx</span>
            <button>+</button>
          </td>
          <td>xxx</td>
        </tr>
      </tbody>
      <tfoot>
        <tr>
          <td colspan="6">合计:xxx</td>
        </tr>
      </tfoot>
    </table>

    <script>
      const products = [
        { name: '苹果', price: 10, count: 30, checked: true },
        { name: '香蕉', price: 6, count: 3, checked: true },
        { name: '柿子', price: 26, count: 1, checked: true },
        { name: '哈密瓜', price: 19, count: 45, checked: true },
      ]

      const products_el = products.map((value, index) => {
        const { count, name, price, checked } = value
        // 添加自定义属性: index, 保存序号
        return `<tr data-index='${index}'>
          <td><input type="checkbox" ${checked ? 'checked' : ''} /></td>
          <td>${index + 1}</td>
          <td>${name}</td>
          <td>¥${price}</td>
          <td>
            <button ${count == 1 ? 'disabled' : ''}>-</button>
            <span>${count}</span>
            <button>+</button>
          </td>
          <td>¥${price * count}</td>
        </tr>`
      })

      document.querySelector('tbody').innerHTML = products_el.join('')

      // 难点1: + 和 -
      // 思路1: 查询所有的按钮, 遍历挨个添加 事件
      // 思路2: 委托 -> 只需要给按钮共同的父元素添加事件
      const tbody = document.querySelector('tbody')
      tbody.onclick = function (e) {
        // 过滤出按钮的点击
        if (e.target.localName == 'button') {
          console.log(e.target)
          // 按钮的 父元素 的 父元素的  自定义属性.index
          const index = e.target.parentElement.parentElement.dataset.index
          console.log('序号:', index)
          // 现在场景: 页面是通过数据数组生成的, 他们应该联动
          if (e.target.innerHTML == '+') {
            products[index].count++
          }
          if (e.target.innerHTML == '-') {
            products[index].count--
          }
          console.log(products)
          //更新对应序号的界面
          updateCell(index)
        }
      }

      // 数据变化后, 要同步更新对应的栏目
      function updateCell(index) {
        // 通过序号, 从tbody孩子中, 找到对应的一条
        const cell = tbody.children[index]
        const subtotal = cell.lastElementChild //小计元素
        // 数量: 小计上方元素的孩子中的序号1
        const count_el = subtotal.previousElementSibling.children[1]
        // 从数据数组中, 读取 单价 和 数量
        const { count, price } = products[index]
        // 把数据 赋值给 元素内容
        count_el.innerHTML = count
        subtotal.innerHTML = '¥' + price * count
        // -按钮
        const jian_el = count_el.previousElementSibling
        // 数量==1 是true, 则说明 不可用是 true
        // jian_el.disabled = count == 1 ? true : false
        jian_el.disabled = count == 1
        // 更新合计
        updateTotal()
      }

      //合计
      function updateTotal() {
        // 数组高阶函数: reduce, 合并归纳数组数据
        // sum是总和, 0是初始值, value是每次遍历的元素
        const total = products.reduce((sum, value) => {
          const { price, count, checked } = value
          // 只累加 勾选的元素的价格, 此处利用 true1 false0
          // 乘以 checked, 如果是false, 不勾选,就是0, 不累加
          return sum + price * count * checked
        }, 0)
        // 获取合计元素
        const total_el = document.querySelector('tfoot td')
        total_el.innerHTML = '合计: ¥' + total
      }
      // 初始时: 触发一次总和
      updateTotal()

      // 全选按钮初始状态:  数组中的每一个都是勾选,则全选真的
      const cha = document.querySelector('thead input')
      // 忘记的人: 回顾 JSCORE 的day03
      cha.checked = products.every(value => value.checked)
      // 全选按钮变化时, 让其他勾选都变化
      cha.onchange = function () {
        //找到其他的所有按钮
        const chs = document.querySelectorAll('tbody input')
        // 遍历每一项, 让其勾选状态 和 全选按钮的一致
        chs.forEach(value => (value.checked = cha.checked))
        // 同步更新数据中的 checked
        products.forEach(value => (value.checked = cha.checked))
        // 重新算总和
        updateTotal()
      }

      // 为每一个单选按钮, 添加change事件:
      const chs = document.querySelectorAll('tbody input')
      chs.forEach(value => {
        value.onchange = function () {
          // 获取序号
          const index = this.parentElement.parentElement.dataset.index
          // 修改对应数据项的checked属性, 与当前选框的 选中状态一样
          products[index].checked = this.checked
          // 更新总价格
          updateTotal()
          // 全选按钮要跟随单选变化: 数据中的每一个元素, 都是勾选才是全选
          cha.checked = products.every(value => value.checked)
        }
      })
    </script>
  </body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值