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

650 阅读4分钟

Web APIs

1. Window对象

1.1 BOM

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

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

  • window 对象下包含了 navigatorlocationdocumenthistoryscreen 5个属性,即所谓的 BOM (浏览器对象模型)
  • document 是实现 DOM 的基础,它其实是依附于 window 的属性。 注:依附于 window 对象的所有属性和方法,使用时可以省略 window

1.2 定时器-延时函数

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

语法:setTimeout('回调函数',等待的毫秒数);

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

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

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

清除延时函数

语法:

let timer = setTimeout('回调函数',等待的毫秒数);
    //清除延时函数:
    clearTimeout(timer)

案例 5秒钟之后消失的广告

需求:5秒钟之后,广告自动消失

分析:

①:设置延时函数

②:隐藏元素

// setTimeout(()=>{
//     document.querySelector('img').style.display = 'none';
// },5000)

setTimeout(function(){
    document.querySelector('img').style.display = 'none';
},5000)

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

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

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

image.png

<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>

1.3 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 是单线程

image.png

  • 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

1.4 location对象

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

常用属性和方法:

  • reload 方法用来刷新当前页面,传入参数 true 时表示强制刷新 image.png
    <button>点击</button>
    <script>
      var btn = document.querySelector('button');
      btn.addEventListener('click', function () {     
        // location.reload(true);  
        console.log(location.hash);
        console.log(location.search);
        // console.log(location.href = 'http://www.itcast.cn');
        console.log(location); 
        // 记录浏览历史,所以可以实现后退功能
        // console.log(location.assign('http://www.itcast.cn')); 
        // 不记录浏览历史,所以不可以实现后退功能
        // location.replace('http://www.itcast.cn');
      });

案例 自动跳转页面

  <body>
    <span>注册成功 5秒后跳转主页</span>
    <a href="www.baidu.com">点击跳转</a>
    <script>
      let c = document.querySelector('span');
      let a = document.querySelector('a');

      function fnn() {
        let b = setInterval(fn, 1000);
        let i = 5;
        function fn() {
          c.innerHTML = `注册成功 ${i}秒后跳转主页 `;
          i--;
          if (i <= 0) {
            clearInterval(b);
            location.href =
              'http://www.itcast.cn';
          //location.assign('http://www.itcast.cn');
          }
        }
      }
      fnn();
    </script>
  </body>

1.5 navigator对象

navigator 对象包含有关浏览器的信息,它有很多属性,我们最常用的是 userAgent,该属性可以返回由客户机发送服务器的 user-agent 头部的值。

下面前端代码可以判断用户那个终端打开页面,实现跳转

if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
    window.location.href = "";     //手机
 } else {
    window.location.href = "";     //电脑
 }
// 检测 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'
}
})()

1.6 histroy对象

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

常用属性和方法:

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

image.png

2. swiper

2.1 插件

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

学习插件的基本过程

3. 本地存储

3.1 本地存储特性

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

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

3.2 localStorage

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

存储数据:

//localStorage.setItem('键','值');
localStorage.setItem('姓名',uname);
localStorage.setItem(('age'),22);
localStorage.setItem(('sex'),1);

获取数据:

localStorage.getItem('键')
//let a = localStorage.getItem('姓名');
// console.log(a);

删除数据:

localStorage.removeItem('键');

存储复杂数据类型存储

本地只能存储字符串,无法存储复杂数据类型.需要将复杂数据类型转换成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);

练习

    <script>
      //变量
      // let uname = '张鹏';

      //本地贮存
      // localStorage.setItem('键','值');
      // localStorage.setItem('姓名',uname);
      // localStorage.setItem(('age'),22);
      // localStorage.setItem(('sex'),1);

      // 获取数据
      // localStorage.getItem('键')

      // let a = localStorage.getItem('姓名');
      // console.log(a);

      // 删除数据
      // localStorage.removeItem('键');

      //引用数据类型
      let obj = {
        uname: 'zp',
        age: 22,
        sex: '男',
      };
      // 将复杂数据转换成JSON字符串 存储 本地存储中
      let a = JSON.stringify(obj);
      console.log(a);
      localStorage.setItem('student', a);
      let b = localStorage.getItem('student');
      console.log(b);
    //   将JSON字符串转换成对象 取出 时候使用
      let c = JSON.parse(b);
      console.log(c);
    </script>

image.png

3.3 sessionStorage(了解)

  1. 生命周期为关闭浏览器窗口
  2. 在同一个窗口(页面)下数据可以共享
  3. 以键值对的形式存储使用
  4. 用法跟localStorage 基本相同

拓展: 自定义属性

固有属性:

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

自定义属性:

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

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

data-自定义属性:

  • 传统的自定义属性没有专门的定义规则,开发者随意定值,不够规范,所以在html5中推出来了专门的data-自定义属性 在
  • 标签上一律以data-开头
  • 在DOM对象上一律以dataset对象方式获取

image.png

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

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

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>1001</td>
        <td>欧阳霸天</td>
        <td>19</td>
        <td>男</td>

        <td>15000</td>
        <td>上海</td>
        <td>
          <a href="javascript:">删除</a>
        </td>
      </tr> -->
      </tbody>
    </table>
    <script>
      //  1. 准备好数据后端的数据
      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: '北京',
        },
      ];

      function getLocalData() {
        let date = localStorage.getItem('date');
        if (date) {
          return JSON.parse(date);
        } else {
          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: '北京',
            },
          ];
        }
        localStorage.setItem('date',JSON.stringify(arr))
        // let a = JSON.stringify(arr);
        // console.log(a);
        // let b = localStorage.setItem('list',a);
        // console.log(b);
      }

      // 获取父元素 tbody
      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');
      // 渲染函数  把数组里面的数据渲染到页面中
      function render() {
        let arr = getLocalData();
        // 先干掉以前的数据  让tbody 里面原来的tr 都没有
        tbody.innerHTML = '';
        // 在渲染新的数据
        // 根据数据的条数来渲染增加 tr
        for (let i = 0; i < arr.length; i++) {
          // 1.创建tr
          let tr = document.createElement('tr');
          // 2.tr 里面放内容
          tr.innerHTML = `
        <td>${arr[i].stuId}</td>
        <td>${arr[i].uname}</td>
        <td>${arr[i].age}</td>
        <td>${arr[i].gender}</td>
        <td>${arr[i].salary}</td>
        <td>${arr[i].city}</td>
        <td>
          <a href="javascript:" id="${i}">删除</a>
        </td>
        `;
          // 3.把tr追加给 tobdy  父元素.appendChild(子元素)
          tbody.appendChild(tr);
        }
      }
      // 页面加载就调用函数
      render();

      add.addEventListener('click', function () {
        let arr = getLocalData();

        if(arr.length === 0){
          stuId = '1001';
        }else{
          stuId: arr[arr.length - 1].stuId + 1;
        }
        // alert(11)
        // 获得表单里面的值   之后追加给 数组 arr  用 push方法
        arr.push({
          // 得到数组最后一条数据的学号 1003    + 1

          stuId: arr[arr.length - 1].stuId + 1,
          uname: uname.value,
          age: age.value,
          gender: gender.value,
          salary: salary.value,
          city: city.value,
        });

        localStorage.setItem('date',JSON.stringify(arr));
        // console.log(arr)
        // 重新渲染我们的函数
        render();
        // 复原所有的表单数据
        uname.value = age.value = salary.value = '';
        gender.value = '男';
        city.value = '北京';
      });

      // 删除操作, 删除的也是数组里面的数据 , 但是我们用事件委托
      tbody.addEventListener('click', function (e) {
        // alert(11)
        // 我们只能点击了链接 a ,才会执行删除操作
        // 那我们怎么知道你点击了a呢?
        // 俺们只能点击了链接才能做删除操作
        // console.dir(e.target.tagName)
        if (e.target.tagName === 'A') {
          // alert('你点击了链接')
          // 删除操作  删除 数组里面的数据  arr.splice(从哪里开始删,1)
          // 我要得到a的id 需要
          // console.log(e.target.id)
          arr.splice(e.target.id, 1);

          // 重新渲染我们的函数

          localStorage.setItem('date',JSON.stringify(arr));
          localStorage.removeItem('date',JSON.stringify(arr))
          render();
        }
      });
    </script>
  </body>
</html>

海到无边天作岸,山登绝顶我为峰。