Web APIs(Window对象(BOM,定时器-延时函数,JS 执行机制,对象),swiper,本地存储)

88 阅读8分钟

一、Window对象

01- BOM

BOM(Browser Object Model ) 是浏览器对象模型

image.png window 是浏览器内置中的全局对象,我们所学习的所有 Web APIs 的知识内容都是基于 window 对象实现的

  • window 对象下包含了 navigatorlocationdocumenthistoryscreen 5个属性,即所谓的 BOM (浏览器对象模型)
  • document 是实现 DOM 的基础,它其实是依附于 window 的属性。

注:依附于 window 对象的所有属性和方法,使用时可以省略 window

02- 定时器-延时函数

JavaScript 内置的一个用来让代码延迟执行的函数,叫 setTimeout

  • 语法:setTimeout('回调函数',等待的毫秒数);
// setTimeout(function(){console.log('回调函数');},1000);

 function fn(){
        console.log('回调函数');
    }
    setTimeout(fn,1000);

setTimeout 仅仅只执行一次,所以可以理解为就是把一段代码延迟执行, 平时省略window

  • 清除延时函数
let timer = setTimeout('回调函数',等待的毫秒数);
    //清除延时函数:
    clearTimeout(timer)
<body>
    <button>延迟执行某个操作</button>
    <button>解除延迟器</button>
    <script>
      let btn1 = document.querySelector('button:nth-of-type(1)')
      let btn2 = document.querySelector('button:nth-of-type(2)')

      // 添加延迟器
      // let 标识 = setTimeout(function() {
      //   //  延迟执行的操作
      // }, 延迟时间)
      let tid
      btn1.addEventListener('click', function() {
        tid = setTimeout(function() {
          console.log(123)
        }, 2000)
      })

      btn2.addEventListener('click', function() {
        // clearTimeout(tid)
        // 通过setTimeout开启的延迟器,通过clearInterval也能清除,反之亦然
        clearInterval(tid)
      })
    </script>
  </body>

03- 5s消失的小广告

<!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>
      img {
        position: absolute;
        left: 0;
        bottom: 0;
      }
    </style>
  </head>

  <body>
    <button>返回</button>
    <img src="./images/ad.png" alt="" />
    <script>
      let btn = document.querySelector('button')
      let img = document.querySelector('img')

      setTimeout(() => {
        img.style.display = 'none'
      }, 5000)

      btn.addEventListener('click', function() {
        // history.back()
        history.go(-10)
      })
    </script>
  </body>
</html>

04-自定义消息提示

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      .tip {
        max-width: 200px;
        padding: 10px 20px;
        background-color: rgba(0, 0, 255, 0.2);
        margin: 200px auto;
        border-radius: 5px;
        text-align: center;
        opacity: 0;
        transition: all 1s;
      }
    </style>
  </head>
  <body>
    <button>登陆</button>
    <div class="tip"></div>
    <script>
      let btn = document.querySelector('button')
      let tip = document.querySelector('.tip')

      // 模拟 框架中的  消息提示:
      // 1.弹出,3秒自动消失 -- 添加延迟器
      // 2.如果鼠标进入,不消失 -- 清除延迟器
      // 3.如果鼠标移开,3秒之后消失 -- 再次添加延迟器

      btn.addEventListener('click', 
      function() {
        tip.innerHTML = '登陆成功'
        tip.style.opacity = 1

        // 显示3s再消失
        let tid = setTimeout(() => {
          tip.style.opacity = 0
        }, 3000)

        // 鼠标进入,清除延迟器
        tip.addEventListener('mouseenter', function() {
          clearTimeout(tid)
        })

        // 鼠标离开,重启延迟器
        tip.addEventListener('mouseleave', function() {
          tid = setTimeout(() => {
            tip.style.opacity = 0
          }, 3000)
        })
      }
    
    )
    </script>
  </body>
</html>

05-利用递归实现setInterval

<body>
    <div></div>
    <script>
      let div = document.querySelector('div')

      // 递归 是指  函数直接或间接调用自身
      function showTime() {
        let time = new Date().toLocaleTimeString()
        div.innerHTML = time

        setTimeout(showTime, 1000)
      }
      showTime()
    </script>
  </body>

05-递归函数:函数内部调用其自身

 function fn(n){
          if(n ===0){
              return;
          }
          fn(n-1)
          console.log(n);
       
      }
      fn(5)

image.png 结合递归函数可以使用 setTimeout 实现 setInterval 一样的功能

<body>
    <div class="clock"></div>
    <script>
      let clock = document.querySelector('.clock');
      function timer() {
        let date = new Date();
        clock.innerHTML = date.toLocaleString();
        setTimeout(timer,1000)
      }
      timer();
      
    </script>

两种定时器对比:

  • setInterval 的特征是重复执行,首次执行会延时
  • setTimeout 的特征是延时执行,只执行 1 次
  • setTimeout 结合递归函数,能模拟 setInterval 重复执行
  • clearTimeout 清除由 setTimeout 创建的定时任务

经典面试题

<script>
console.log(111);
setTimeout(function(){
    console.log(222);
},1000)
console.log(333);

//111
//333
//222

console.log(111);
setTimeout(function(){
    console.log(222);
},1000)
console.log(333);
//111
//333
//222
</script>

06- JS 执行机制

以下代码执行的结果是什么?

 console.log(1);
 
 setTimeout(function () {
     console.log(3);
 }, 1000);
 
 console.log(2);//1,3,2
console.log(1);
 
 setTimeout(function () {
     console.log(3);
 }, 0);
 
 console.log(2);//1,3,2

JS 是单线程

JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。 这是因为 Javascript 这门脚本语言诞生的使命所致——JavaScript 是为处理页面中用户的交互,以及操作 DOM 而诞生的。比如我们对某个 DOM 元素进行添加和删除操作,不能同时进行。 应该先进行添加,之后再删除。

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。这样所导致的问题是: 如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。

同步任务和异步任务

单线程导致的问题就是后面的任务等待前面任务完成,如果前面任务很耗时(比如读取网络数据),后面任务不得不一直等待!!

为了解决这个问题,利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,但是子线程完全受主线程控制。于是,JS 中出现了同步任务异步任务

同步

前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。比如做饭的同步做法:我们要烧水煮饭,等水开了(10分钟之后),再去切菜,炒菜。

异步

你在做一件事情时,因为这件事情会花费很长时间,在做这件事的同时,你还可以去处理其他事情。比如做饭的异步做法,我们在烧水的同时,利用这10分钟,去切菜,炒菜。

他们的本质区别: 这条流水线上各个流程的执行顺序不同。

JS中所有任务可以分成两种

  1. 同步任务(synchronous)

在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务; 2. 异步任务(asynchronous) 不进入主线程、而进入”任务队列”的任务,当主线程中的任务运行完了,才会从”任务队列”取出异步任务放入主线程执行。

image.png

JS执行机制(事件循环)

  1. 先执行执行栈中的同步任务。
  2. 异步任务放入任务队列中。
  3. 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。

image.png 思考:

console.log(1)
document.addEventListener('click', function () {
console.log(4)
})
console.log(2)
setTimeout(function () {
console.log(3)
}, 3000)

图例小结

image.png

image.png

07- location对象

  • location 的数据类型是对象,它拆分并保存了 URL 地址的各个组成部分

  • 常用属性和方法:

    • href 属性获取完整的 URL 地址,对其赋值时用于地址的跳转
    • search 属性获取地址中携带的参数,符号 ?后面部分
    • hash 属性获取地址中的啥希值,符号 # 后面部分 VUE中使用
    • reload 方法用来刷新当前页面,传入参数 true 时表示强制刷新
    • reload 方法用来刷新当前页面,传入参数 true 时表示强制刷新

    image.png

<body>
    <button>帮我跳转到某个页面</button>
    <script>
      let btn = document.querySelector('button')
      btn.addEventListener('click', function() {
        // location.href
        // 1.没有赋值就是取值
        // 2.赋值正确的地址就可以实现跳转
        // 跳转的路径可以是  绝对路径也可以是相对路径
        // location.href = "https://www.baidu.com/s?wd=%E8%91%B1%E7%88%86%E8%82%89&rsv_spt=1&rsv_iqid=0xcdf6be0000002179&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=02003390_19_hao_pg&rsv_dl=ib&rsv_enter=1&rsv_sug3=4&rsv_sug1=2&rsv_sug7=100"

        // location.href = './03-5秒消失的广告.html'

        location.reload()
      })
    </script>
  </body>

08-5秒钟之后跳转页面

<!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>
      span {
        color: red;
      }
    </style>
  </head>

  <body>
    <button>forward</button>
    <a href="./13-history对象.html">支付成功,<span>5</span> 秒之后跳转首页</a>
    <script>
      // 如果单击,则自动的跳转,如果不单击则5秒之后自动跳转
      let span = document.querySelector('span')
      let button = document.querySelector('button')

      button.addEventListener('click', function() {
        location.href = './03-5秒消失的广告.html'
      })

      let time = 5
      // setTimeout(() => {}, 5000)

      setInterval(function() {
        time--
        span.innerText = time
        if (time == 0) {
          location.href = './03-5秒消失的广告.html'
        }
      }, 1000)
    </script>
  </body>
</html>

09- navigator对象

  • navigator的数据类型是对象,该对象下记录了浏览器自身的相关信息
  • 常用属性和方法:
    • 通过 userAgent 检测浏览器的版本及平台 自动检测移动端并跳转 navigator 对象包含有关浏览器的信息,它有很多属性,我们最常用的是 userAgent,该属性可以返回由客户机发送服务器的 user-agent 头部的值。 下面前端代码可以判断用户那个终端打开页面,实现跳转
<script>
      // 检测 userAgent(浏览器信息)
      !(function() {
        const userAgent = navigator.userAgent
        // 验证是否为Android或iPhone
        const android = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/)
        const iphone = userAgent.match(/(iPhone\sOS)\s([\d_]+)/)
        // 如果是Android或iPhone,则跳转至移动站点
        if (android || iphone) {
          location.href = 'http://m.itcast.cn'
        } else {
          location.href = 'http://itcast.cn'
        }
      })()
    </script>

1.6 histroy对象

history 的数据类型是对象,该对象与浏览器地址栏的操作相对应,如前进、后退、历史记录等

常用属性和方法:

image.png history 对象一般在实际开发中比较少用,但是会在一些 OA 办公系统中见到。

image.png

2. swiper插件

01- 插件

插件: 就是别人写好的一些代码,我们只需要复制对应的代码,就可以直接实现对应的效果

学习插件的基本过程

3. 本地存储

01- 本地存储特性

随着互联网的快速发展,基于网页的应用越来越普遍,同时也变的越来越复杂,为了满足各种各样的需求,会经常性在本地存储大量的数据,HTML5规范提出了相关解决方案。

  1. 数据存储在用户浏览器中
  2. 设置、读取方便、甚至页面刷新不丢失数据
  3. 容量较大,sessionStorage和localStorage约 5M 左右

02- localStorage

  1. 生命周期永久生效,除非手动删除 否则关闭页面也会存在
  2. 可以多窗口(页面)共享(同一浏览器可以共享)
  3. 以键值对的形式存储使用

03- 本地存储使用

<body>
    <button>设置本地存储</button>
    <button>获取本地存储</button>
    <button>删除本地存储</button>
    <button>干掉所有本地存储</button>
    <script>
      let set = document.querySelector('button:nth-of-type(1)')
      let get = document.querySelector('button:nth-of-type(2)')
      let remove = document.querySelector('button:nth-of-type(3)')
      let clear = document.querySelector('button:nth-of-type(4)')

      // 存储数据到本地存储
      set.addEventListener('click', function() {
        // 语法:localStorage.setItem('自定义键','字符串值')
        localStorage.setItem('key79', '随便写一个字符串就可以了')
      })

      get.addEventListener('click', function() {
        // 语法:localStorage.getItem('键'):获取当前键所对应的值,如果没有这个键,则返回null
        let v = localStorage.getItem('key79')
        console.log(v)
      })

      remove.addEventListener('click', function() {
        // 语法:localStorage.removeItem('键'):删除指定名称的本地存储:整个键值对都删除
        // 键如果不存在,没事。。
        localStorage.removeItem('key79')
      })

      clear.addEventListener('click', function() {
        // localStorage.clear():删除浏览器的所有本地存储--慎用
        localStorage.clear()
      })
    </script>
  </body>

04-本地存储存储的和获取的都是字符串

 <body>
    <button>设置本地存储</button>
    <button>获取本地存储</button>
    <button>删除本地存储</button>

    <script>
      let set = document.querySelector('button:nth-of-type(1)')
      let get = document.querySelector('button:nth-of-type(2)')
      let remove = document.querySelector('button:nth-of-type(3)')

      set.addEventListener('click', function() {
        // let obj = { username: '黄鑫', age: 20 }
        let arr = [1, 3, 5, 7, 9]
        // 1.本地存储只能存储字符串格式,如果你传递的数据不是字符串,那么它会自动将数据转换为字符串
        localStorage.setItem('key-79-info', arr)
      })
    </script>
  </body>

存储复杂数据类型存储

本地只能存储字符串,无法存储复杂数据类型.需要将复杂数据类型转换成JSON字符串,在存储到本地

JSON.stringify(复杂数据类型)

将复杂数据转换成JSON字符串 存储 本地存储中

 let a = JSON.stringify(obj);
 console.log(a);
      localStorage.setItem('student', a);
 let b = localStorage.getItem('student');
 console.log(b);

JSON.parse(JSON字符串)

将JSON字符串转换成对象 取出 时候使用

let c = JSON.parse(b);
console.log(c);

05- 本地存储存储数组

<body>
    <button>设置本地存储</button>
    <button>获取本地存储</button>
    <button>删除本地存储</button>
    <button>干掉所有本地存储</button>
    <script>
      let arr = [
        {
          stuId: 1001,
          uname: '欧阳霸天',
          age: 19,
          gender: '男',
          salary: '20000',
          city: '上海'
        },
        {
          stuId: 1002,
          uname: '令狐霸天',
          age: 29,
          gender: '男',
          salary: '30000',
          city: '北京'
        },
        {
          stuId: 1003,
          uname: '诸葛霸天',
          age: 39,
          gender: '男',
          salary: '2000',
          city: '北京'
        }
      ]
      let set = document.querySelector('button:nth-of-type(1)')
      let get = document.querySelector('button:nth-of-type(2)')

      set.addEventListener('click', function() {
        // localStorage.setItem('key79', arr)
        // let obj = {
        //   stuId: 1001,
        //   uname: '欧阳霸天',
        //   age: 19,
        //   gender: '男',
        //   salary: '20000',
        //   city: '上海'
        // }
        // // 将obj转换为对象的字符串格式 -- json格式
        // // JSON.stringify(对象) 》》json字符串
        // localStorage.setItem('key79', JSON.stringify(obj))

        // let arr = [1, 3, 5, 7, 9]
        // localStorage.setItem('key79', JSON.stringify(arr))

        localStorage.setItem('key79', JSON.stringify(arr))
      })

      get.addEventListener('click', function() {
        // 获取到的本地存储数据默认是字符串
        // JSON.parse(json字符串):将json字符串转换为js对象(数组)
        let v = localStorage.getItem('key79')
        console.log(v, typeof v)
        console.log(JSON.parse(v), typeof JSON.parse(v))
        // 面向对象编程
      })
    </script>
  </body>

06- sessionStorage(了解)

  1. 生命周期为关闭浏览器窗口
  2. 在同一个窗口(页面)下数据可以共享
  3. 以键值对的形式存储使用
  4. 用法跟localStorage 基本相同
<body>
    <button>设置本地存储</button>
    <button>获取本地存储</button>
    <button>删除本地存储</button>
    <script>
      let set = document.querySelector('button:nth-of-type(1)')
      let get = document.querySelector('button:nth-of-type(2)')
      let remove = document.querySelector('button:nth-of-type(3)')

      set.addEventListener('click', function() {
        sessionStorage.setItem('aa', 'aaaaa')
      })
    </script>
  </body>

07- 综合案例 本地存储学习信息案例

需求:改为本次存储版本的学习信息表

image.png 分析:

需求①:读取本地存储数据(封装函数)

如果本地存储有数据,则返回 JSON.parse() 之后的对象

如果本地存储没有数据,则默认写入三条数据,注意存储的利用JSON.stringify() 存 储JSON 格式的数据

需求②:渲染模块

先读取本地存储数据,然后渲染

需求③:添加模块

注意,先取的最新的本地存储数据,然后追加

新增了数据,要把新数据存储到本地存储别,忘记转换

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

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Document</title>
  <link rel="stylesheet" href="css/user.css" />
</head>

<body>
  <h1>新增学员</h1>
  <div class="info">
    姓名:<input type="text" class="uname" /> 年龄:<input type="text" class="age" />
    性别:
    <select name="gender" id="" class="gender">
      <option value="男"></option>
      <option value="女"></option>
    </select>
    薪资:<input type="text" class="salary" /> 就业城市:<select name="city" id="" class="city">
      <option value="北京">北京</option>
      <option value="上海">上海</option>
      <option value="广州">广州</option>
      <option value="深圳">深圳</option>
      <option value="曹县">曹县</option>
    </select>
    <button class="add">录入</button>
  </div>

  <h1>就业榜</h1>
  <table>
    <thead>
      <tr>
        <th>学号</th>
        <th>姓名</th>
        <th>年龄</th>
        <th>性别</th>
        <th>薪资</th>
        <th>就业城市</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <!-- <tr>
        <td>1</td>
        <td>这是名称</td>
        <td>这是年龄</td>
        <td>这是性别</td>
        <td>这是工资</td>
        <td>这是所在城市</td>
        <td>
          <a href="javascript:" class="del">删除</a>
        </td>
      </tr> -->
    </tbody>
  </table>
  <script>
    // 模拟数据:数据一定要有id作为数据的唯一标识,这个标识是以后数据 修改和删除的凭证
    let students = JSON.parse(localStorage.getItem('userinfo-79')) || [
      {
      id: 1,
      name: '张三',
      age: 18,
      gender: '男',
      salary: 18000,
      city: '广州'
      },
      {
      id: 2,
      name: '李四',
      age: 19,
      gender: '男',
      salary: 20000,
      city: '深圳'
      },
      {
      id: 3,
      name: '王五',
      age: 18,
      gender: '男',
      salary: 18000,
      city: '广州'
      },
      {
      id: 4,
      name: '赵六',
      age: 19,
      gender: '男',
      salary: 20000,
      city: '深圳'
      }
    ]
    // 获取元素
    let tbody = document.querySelector('tbody')
    let add = document.querySelector('.add')
    let uname = document.querySelector('.uname')
    let age = document.querySelector('.age')
    let gender = document.querySelector('.gender')
    let salary = document.querySelector('.salary')
    let city = document.querySelector('.city')
    let id = 5
    // 1.数据渲染
    function init(){
      // 遍历拼接
      let htmlStr = '';
      students.forEach(function(value,index){
        htmlStr += `<tr>
                    <td>${index + 1}</td>
                    <td>${value.name}</td>
                    <td>${value.age}</td>
                    <td>${value.gender}</td>
                    <td>${value.salary}</td>
                    <td>${value.city}</td>
                    <td>
                      <a href="javascript:" class="del" id="${value.id}">删除</a>
                    </td>
                  </tr>`
      })
      tbody.innerHTML = htmlStr;
    }
    // 一开始需要调用函数,否则函数不会自动的执行
    init()

    // 2.使用事件委托绑定事件,一般情况下是绑定给最近的一级父容器
    tbody.addEventListener('click',function(e){
      // 判断是否是单击了删除按钮
      if(e.target.className == 'del'){
        // console.log(e.target);
        // 实现删除:filter方法的使用
        // filter是数组非变更方法,所以要将filter的结果覆盖原数组
        students = students.filter(function(value){
          // 假如删除id为1的值
          return value.id != e.target.id
        })
        // 重新渲染
        init()
        localStorage.setItem('userinfo-79', JSON.stringify(students))
      }
    })

    // 3.添加数据
    add.addEventListener('click', function(){
      // 创建新的数组对象
      let newObj = {
        id: id,
        name: uname.value,
        age: age.value,
        gender: gender.value,
        salary: salary.value,
        city: city.value
      }
      id++
      // 将新创建的对象添加到数组中
      students.push(newObj);
      // 重新渲染数据
      init()

      // 存储本地数据
      localStorage.setItem('userinfo-79', JSON.stringify(students))
    })

  </script>
</body>

</html>

拓展: 自定义属性

  • 固有属性:

    • 标签天生自带的属性 比如class id title等, 可以直接使用点语法操作
  • 自定义属性:

    由程序员自己添加的属性,在DOM对象中找不到, 无法使用点语法操作,必须使用专门的API

    • getAttribute('属性名') // 获取自定义属性
    • setAttribute('属性名', '属性值') // 设置自定义属性
    • removeAttribute('属性名') // 删除自定义属性

自定义属性操作api

<body>
    <p index="1" class="abc">我是p元素</p>
    <input type="checkbox" checked />
    <button>添加一个自定义属性</button>
    <button>获取一个自定义属性</button>
    <button>移除一个自定义属性</button>

    <script>
      let p = document.querySelector('p')
      let input = document.querySelector('input')
      let btn1 = document.querySelector('button:nth-of-type(1)')
      let btn2 = document.querySelector('button:nth-of-type(2)')
      let btn3 = document.querySelector('button:nth-of-type(3)')

      btn1.addEventListener('click', function() {
        p.setAttribute('myname', 'jack')
        p.setAttribute('id', 'jack')
      })

      btn2.addEventListener('click', function() {
        // 结论:通过 元素.属性只能获取内置属性的值,不能获取非内置属性的值
        // console.log(p.index)
        // getAttribute('自定义属性名称'):可以获取内置和非内置属性的值,但是它不能获取状态值(checked...)
        // 最大缺点:获取值的时候一次只能获取一个自定义属性值,并且调用api赋值完全不适合遍历拼接(动态渲染)
        console.log(p.getAttribute('class'))
        console.log(input.getAttribute('checked'))
      })

      btn3.addEventListener('click', function() {
        p.removeAttribute('myname')
      })
    </script>
  </body>

data-自定义属性:

  • 传统的自定义属性没有专门的定义规则,开发者随意定值,不够规范,所以在html5中推出来了专门的data-自定义属性 在
  • 标签上一律以data-开头
  • 在DOM对象上一律以dataset对象方式获取
<body>
    <!-- 自定义属性的规范,以data-开头  如  data-myname='jack' -->
    <p class="red" data-name="jack" data-age="20" data-gender="男">
      我是p元素
    </p>
    <button>获取自定义属性的值</button>
    <script>
      let btn = document.querySelector('button')
      let p = document.querySelector('p')
      btn.addEventListener('click', function() {
        // 获取p元素的自定义属性值
        // 通过元素的dataset属性获取所有data-开头的自定义属性值,返回一个对象
        console.log(p.dataset)
        console.log(p.dataset.name)
      })
    </script>
  </body>

自定义属性的应用场景

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      div {
        width: 400px;
        height: 400px;
        border: solid;
      }
    </style>
  </head>
  <body>
    <!-- 自定义属性:非内置属性
  img.src   p.id  input.value -->
    <table border="1" width="400">
      <thead>
        <tr>
          <th>学号</th>
          <th>姓名</th>
          <th>年龄</th>
          <th>性别</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <!-- <tr>
          <td>学号</td>
          <td>姓名</td>
          <td>年龄</td>
          <td>性别</td>
          <td><a href="#">编辑</a></td>
        </tr> -->
      </tbody>
    </table>

    <div>
      姓名: <input type="text" class="username" /> <br />
      年龄 <input type="text" class="userage" /> <br />
      性别 <input type="text" class="usergender" /> <br />
      <button class="userEdit">编辑</button>
    </div>

    <script>
      let username = document.querySelector('.username')
      let userage = document.querySelector('.userage')
      let usergender = document.querySelector('.usergender')
      let tbody = document.querySelector('tbody')
      let userEdit = document.querySelector('.userEdit')
      let datas = [
        { id: 1, name: 'jack', age: 20, gender: '男' },
        { id: 2, name: 'rose', age: 19, gender: '女' },
        { id: 3, name: 'tom', age: 18, gender: '男' }
      ]

      // 渲染学员列表 -- 封装为函数,方便后期数据操作之后的重新渲染 
      function init(){
        let htmlStr = ''
        datas.forEach(function(v, i){
          htmlStr += `<tr>
                        <td>${i + 1}</td>
                        <td>${v.name}</td>
                        <td>${v.age}</td>
                        <td>${v.gender}</td>
                        <td>
                          <a href="javascript:;" class="edit" data-username="${v.name}" data-userage="${v.age}" data-usergender="${v.gender}" data-id="${v.id}">编辑</a>
                        </td>
                      </tr>`
        })
        tbody.innerHTML = htmlStr
      }
      init()
      
      let editId;
      // 动态元素的事件绑定需要使用事件委托
      // 单机列表中的 编辑 仅仅是进行数据回填  -- 没有做编辑操作
      tbody.addEventListener('click', function(e){
        // 判断
        if(e.target.className == 'edit'){
          // 获取当前所编辑的数据进行回填
          // dataset:可以获取当前元素所有data-开头的自定义属性值,返回一个对象
          let data = e.target.dataset
          console.log(data);  // DOMStringMap {username: 'jack', userage: '20', usergender: '男'}
          editId = data.id
          console.log(editId);
          username.value = data.username
          userage.value = data.userage
          usergender.value = data.usergender
        }
      })

      // 实现真正的编辑
      userEdit.addEventListener('click', function(){
        // 基于数据id进行编辑
        // 我要id --- editId
        // 1.根据id找到索引
        for(let i = 0; i < datas.length; i++){
          if(datas[i].id == editId){
            // 2.根据索引进行数据编辑
            datas[i].name = username.value
            datas[i].age = userage.value
            datas[i].gender = usergender.value
            break;
          }
        }
        init()
      })
    </script>
  </body>
</html>