web-api

1 - WEB API介绍

1.1 API的概念

API(Application Programming Interface,应⽤程序编程接⼝)是⼀些预先定义的函数,⽬的是提

供应⽤程序与开发⼈员基于某软件或硬件得以访问⼀组例程的能⼒,⽽⼜⽆需访问源码,⽆需理解其内

部⼯作机制细节,只需直接调⽤使⽤即可。

举例解释什么是API。
例如,
C语⾔中有⼀个函数 fopen()可以打开硬盘上的⽂件,这个函数对于我们来说,就是⼀个C语⾔提
供的打开⽂件的⼯具。
javascript中有⼀个函数alert()可以在⻚⾯弹⼀个提示框,这个函数就是js提供的⼀个弹框⼯具。
这些⼯具(函数)由编程语⾔提供,内部的实现已经封装好了,我们只要学会灵活的使⽤这些⼯具
即可。

1.2 Web API的概念

Web API 是浏览器提供的⼀套操作浏览器功能和⻚⾯元素的 API ( BOM 和 DOM )。

现阶段我们主要针对于浏览器讲解常⽤的 API , 主要针对浏览器做交互效果。⽐如我们想要浏览器弹出

⼀个警示框, 直接使⽤ alert(‘弹出’)

MDN 详细 API : https://developer.mozilla.org/zh-CN/docs/Web/API

因为 Web API 很多,所以我们将这个阶段称为 Web APIs。

此处的 Web API 特指浏览器提供的⼀系列API(很多函数或对象⽅法),即操作⽹⻚的⼀系列⼯具。例

如:操作html标签、操作⻚⾯地址的⽅法。

1.3 API 和 Web API 总结

  1. API 是为我们程序员提供的⼀个接⼝,帮助我们实现某种功能,我们会使⽤就可以了,不必纠结内部如何实现

  2. Web API 主要是针对于浏览器提供的接⼝,主要针对于浏览器做交互效果。

  3. Web API ⼀般都有输⼊和输出(函数的传参和返回值),Web API 很多都是⽅法(函数)

  4. 学习 Web API 可以结合前⾯学习内置对象⽅法的思路学习

2 - DOM

DOM 就是把⻚⾯看成是⼀个⽂档,学习DOM就是学习操作⽂档⾥的元素。DOM⼜称为⽂档树模型

DOM树:把html⻚⾯或者是xml⽂件看成是⼀个⽂档,⽂档就是⼀个对象,这个⽂档中所有的标签都是

元素,元素也可以看成是对象,标签(元素、对象)有很多,还有嵌套关系组成的这种层次结构,可以

模拟成树形结构图,简称:树状图,就是dom树

DOM对象:通过DOM⽅式获取的元素得到的对象

⽂档 ⼀个⽹⻚可以称为⽂档

节点(node):⻚⾯中所有的内容都是节点(包括标签、属性、⽂本(⽂字、换⾏、空格、回⻋)、注释

等)

元素(elementt):⻚⾯中所有的标签都是元素,元素可以看成是对象。

根元素:html标签

⻚⾯中的顶级对象:document

属性 标签的属性

HTML⽂件是⽤来展示信息,展示数据的 XML:侧重于存储数据

HTML ⽂件看成是⼀个⽂档(document),把这个⽂档也可以看成是⼀个对象,⽂档中所有的标签都

可以看成是⼀个对象

DOM结构树(继承关系)

image-20210802144503056

DOM结构树上相关联的有这个继承的关系,例如在 HTMLElement.abc=123 ,那么在它的分⽀下的任何

⼀个拥有继承关系的分⽀上,都会有这个属性。⽐如在⻚⾯中选中⼀个元素,那么这个元素身上也有

abc=123这个属性。

document.__proto__ ==> HTMLDocument
HTMLDocument.__proto__ ==> Document
Document.__proto__ ==> Node
Node.__proto__ ==> EventTarget
EventTarget.__proto__ ==> Object

2.1 DOM 常⻅的操作简介

  • 获取元素
  • 动态创建元素
  • 对元素进⾏操作(设置其属性或调⽤其⽅法)
  • 事件(什么时机做相应的操作)

1、 getElementByid ⽅法定义在 Document.prototype 上,即 Element 节点上不能使⽤。

2、 getElementsByName ⽅法定义在 HTMLDocument.prototype 上,即⾮ html 中的 document 不能使⽤

( xml documentElement )

3、 getElementsByTagName ⽅法定义在 Document.prototype 和 Element.prototype 上,换句话说就

是获取到的元素可以继续调⽤ getElementsByTagName 这个⽅法。

4、 HTMLDocument.prototype 定义了⼀些常⽤的属性, body.head 分别指代 HTML ⽂档中的

标签

5、 Document.prototype 上定义了 documentElement 属性,指代⽂档的根元素,在 HTML ⽂档中,他总

是指代 元素。

6 、 getELementsByClassName 、 querySelectorAll 、 querySelector

在 Docuement.prototype , Element.prototype 类中均有定义。

2.2 获取⻚⾯元素的⽅法

除了id,其他的选择器取出来的都是⼀组的,基本上全部是类数组
1、根据id属性获取元素 返回的是⼀个元素对象 getElementById("id")
2、根据标签名获取元素 返回的是元素对象组成的伪数组 getElementsByTagName("标签的名⼦")
下⾯的⼏个,有的浏览器不⽀持
3 、根据表单的 name 属性获取元素,返回的是元素对象组成的⼀个伪数组
getElementsByName("name属性")
<body> <input type="button" value="更改value值" id="btn"> <input type="text" name="name1" value="我很好"> <br/>
<input type="text" name="name2" value="我很好"> <br/>
<input type="text" name="name1" value="我很好"> <br/>
<input type="text" name="name3" value="我很好"> <br/>
<input type="text" name="name3" value="我很好"> <br/>
<script >
// 根据表单的name属性获取元素 把name是1的获取出来
document.getElementById("btn").onclick = function () {
// document.getElementsByName("name属性值")是根据表单的name属性获取元
素,返回的也是⼀个伪数组
var nameList = document.getElementsByName("name1");
for (var i=0; nameList.length; i++) {
nameList[i].value = "你好呀";
 }
 };
</script>
</body>

4、根据类样式的名⼦来获取元素,返回的是元素对象组成的伪数组 getElementsByClassName("类名⼦")

<head><meta charset="UTF-8"> <title>Title</title>
<style>
div {
 100px;
height: 100px;
background-color: #f40;
 }
span {
display: block;
 100px;
height: 100px;
background-color: yellow;
 }
</style>
</head>
<body> <div class="cls">这是第⼀个div</div>
<div class="cls">这是第⼆个div</div>
<span class="cls">span</span>
<input type="button" value="变颜⾊" id="btn"> <script src="./common.js"></script>
<script >
// 根据类样式获取元素 注意ie8及以下都不⽀持
my$("btn").onclick = function () {
// document.getElementsByClassName("类样式名⼦") 根据类样式获取元素,返
回的也是⼀个伪数组
var classList = document.getElementsByClassName("cls");
for (var i=0; i<classList.length; i++) {
classList[i].style.backgroundColor="pink";
 }
 };
</script>
</body>

5、根据css选择器获取元素,返回来的是⼀个元素对象 querySelector("选择器名字"),并不常⽤,选择

出来的东⻄不是时事的zz(H5新增的)

6、根据css选择器获取元素,返回的是元素对象组成的伪数组 querySelectorAll("选择器的名字") 注意

⾥⾯的选择器要加符号。⽐如 document.queryselector(".class/#id")

7、获取特殊的元素(body, html)

获取 body 元素 : document.body

获取 html 元素 : document.documentElement

3 - 事件 基础

3.1. 事件概述

JavaScript 使我们有能⼒创建动态⻚⾯,⽽事件是可以被 JavaScript 侦测到的⾏为。

简单理解: 触发--- 响应机制。

⽹⻚中的每个元素都可以产⽣某些可以触发 JavaScript 的事件,例如,我们可以在⽤户点击某按钮时

产⽣⼀个 事件,然后去执⾏某些操作。

3.2 事件的三要素

  • 事件源(谁):触发事件的元素
  • 事件类型(什么事件): 例如 click 点击事件
  • 事件处理程序(做啥):事件触发后要执⾏的代码(函数形式),事件处理函数
<body><button id="btn">唐伯⻁</button>
<script>
// 点击⼀个按钮,弹出对话框
// 1. 事件是有三部分组成 事件源 事件类型 事件处理程序 我们也称
为事件三要素
//(1) 事件源 事件被触发的对象 谁 按钮
var btn = document.getElementById('btn');
//(2) 事件类型 如何触发 什么事件 ⽐如⿏标点击(onclick) 还是⿏标经过
还是键盘按下
//(3) 事件处理程序 通过⼀个函数赋值的⽅式 完成
btn.onclick = function() {
alert('点秋⾹');
 }
</script>
</body>

3.3 事件执⾏的步骤

  1. 获取事件源

  2. 注册事件

  3. 添加事件处理程序

案例代码

<body><div>123</div>
<script>
// 执⾏事件步骤
// 点击div 控制台输出 我被选中了
// 1. 获取事件源
var div = document.querySelector('div');
// 2.绑定事件 注册事件
// div.onclick
// 3.添加事件处理程序
div.onclick = function() {
console.log('我被选中了');
 }
</script>
</body>

3.4 常⻅的⿏标事件

image-20210802144852148

3.5 分析事件三要素

  • 下拉菜单三要素

  • 关闭⼴告三要素

4 - 操作属性

JavaScript的 DOM 操作可以改变⽹⻚内容、结构和样式,我们可以利⽤ DOM 操作元素来改变元素⾥

⾯的内容、属性等。(注意:这些操作都是通过元素对象的属性实现的)

4.1. 改变元素内容(获取或设置)

image-20210802144945944

innerText改变元素内容

<body><button>显示当前系统时间</button>
<div>某个时间</div>
<p>1123</p>
<script>
// 当我们点击了按钮, div⾥⾯的⽂字会发⽣变化
// 1. 获取元素
var btn = document.querySelector('button');
var div = document.querySelector('div');
// 2.注册事件
btn.onclick = function() {
// div.innerText = '2019-6-6';
div.innerHTML = getDate();
 }
function getDate() {
var date = new Date();
// 我们写⼀个 2019年 5⽉ 1⽇ 星期三
var year = date.getFullYear();
var month = date.getMonth() + 1;
var dates = date.getDate();
var arr = ['星期⽇', '星期⼀', '星期⼆', '星期三', '星期四', '星期
五', '星期六'];
var day = date.getDay();
    return '今天是:' + year + '年' + month + '⽉' + dates + '⽇ ' +
arr[day];
 }
</script>
</body>

innerTextinnerHTML的区别

  • innerText主要是设置⽂本的,设置标签内容,是没有标签的效果的,同时会把标签内的所有内容(包括包含的标签)都替换为新的内容 ⽂本的形式
  • innerHTML 可以设置⽂本内容,主要作⽤是在标签中设置新的html标签内容,是有标签的效果的,同时把标签内的所有内容(包括包含的标签)都替换成
  • 新的内容 解析成html代码的形式
  • innerText 获取的时候,会把标签内的所有的⽂本内容到取到。包括嵌套的标签⾥的内容,⽂本的形式
  • innerHTML 获取的时候,会把标签内的所有内容,原样获取到,html代码的形式

案例代码

<body><div></div>
<p>
  我是⽂字
  <span>123</span>
</p>
<script>
  // innerText 和 innerHTML的区别
  // 1. innerText 不识别html标签 ⾮标准 去除空格和换⾏
  var div = document.querySelector('div');
  // div.innerText = '<strong>今天是:</strong> 2019';
  // 2. innerHTML 识别html标签 W3C标准 保留空格和换⾏的
  div.innerHTML = '<strong>今天是:</strong> 2019';
  // 这两个属性是可读写的 可以获取元素⾥⾯的内容
  var p = document.querySelector('p');
  console.log(p.innerText);
  console.log(p.innerHTML);
</script>
</body>

innerText改变元素内容

<body><button>显示当前系统时间</button>
<div>某个时间</div>
<p>1123</p>
<script>
  // 当我们点击了按钮, div⾥⾯的⽂字会发⽣变化
  // 1. 获取元素
  var btn = document.querySelector('button');
  var div = document.querySelector('div');
  // 2.注册事件
  btn.onclick = function() {
// div.innerText = '2019-6-6';
    div.innerHTML = getDate();
  }
  function getDate() {
    var date = new Date();
// 我们写⼀个 2019年 5⽉ 1⽇ 星期三
    var year = date.getFullYear();
    var month = date.getMonth() + 1;
    var dates = date.getDate();
    var arr = ['星期⽇', '星期⼀', '星期⼆', '星期三', '星期四', '星期
      五', '星期六'];
    var day = date.getDay();
    return '今天是:' + year + '年' + month + '⽉' + dates + '⽇ ' +
      arr[day];
  }
</script>
</body>

innerText和innerHTML的区别

  • 获取内容时的区别:

innerText会去除空格和换⾏,⽽innerHTML会保留空格和换⾏

  • 设置内容时的区别:

innerText不会识别html,⽽innerHTML会识别

案例代码

<body><div></div>
<p>
  我是⽂字
  <span>123</span>
</p>
<script>
  // innerText 和 innerHTML的区别
  // 1. innerText 不识别html标签 ⾮标准 去除空格和换⾏
  var div = document.querySelector('div');
  // div.innerText = '<strong>今天是:</strong> 2019';
  // 2. innerHTML 识别html标签 W3C标准 保留空格和换⾏的
  div.innerHTML = '<strong>今天是:</strong> 2019';
  // 这两个属性是可读写的 可以获取元素⾥⾯的内容
  var p = document.querySelector('p');
  console.log(p.innerText);
  console.log(p.innerHTML);
</script>
</body>

innerText和textContent兼容性

  • 设置标签中的⽂本内容,应该使⽤textContent属性,⾕歌、⽕狐⽀持,ie8不⽀持
  • 设置标签中的⽂本内容,应该使⽤innerText属性,⾕歌、ie8⽀持,⾼版本的⽕狐⽀持,低版本的不⽀持
  • 如果这个属性在浏览器中不⽀持,那么这个属性的类型是undefined,判断这个属性的类型是不是undefined,就知道浏览器⽀不⽀持。
<body><input type="button" value="设置" id="btn"> <input type="button" value="获取" id="btn1">
<div id="dv">螺蛳粉就算了</div>
<script src="./common.js"></script>
<script>// 设置标签中的⽂本内容,应该使⽤textContent属性,⾕歌、⽕狐⽀持,ie8不⽀持// 设置标签中的⽂本内容,应该使⽤innerText属性,⾕歌、ie8⽀持,⾼版本的⽕狐⽀持,低版本的不⽀持// 如果这个属性在浏览器中不⽀持,那么这个属性的类型是undefined,判断这个属性的类型是不是undefined,就知道浏览器⽀不⽀持。// ** 写解决兼容性的函数// 1、设置标签中的⽂本内容function setInnerText (element, text) {if (typeof element.textContent=="undefined") {//说明不⽀持element.innerText = text; }else {element.textContent = text; } }// 2、获取标签中的⽂本内容function getInnerText (element) {if (typeof element.textContent == "undefined") {return element.innerText; } else {return element.textContent; } }// 测试设置my$("btn").onclick = function () {// 设置div中的⽂本内容setInnerText(my$("dv"), "⽼司机服务"); };// 测试获取my$("btn1").onclick = function () {// 获取div中的内容var out = getInnerText(my$("dv"));console.log(out); };</script>
</body>

4.2 常⽤元素的属性操作

  1. src、href

  2. id、 alt、title

获取属性的值

​ 元素对象.属性名

设置属性的值

​ 元素对象.属性名 = 值

案例代码

<body><button id="ldh">刘德华</button>
<button id="zxy">张学友</button> <br>
<img src="images/ldh.jpg" alt="" title="刘德华"> <script>
  // 修改元素属性 src
  // 1. 获取元素
  var ldh = document.getElementById('ldh');
  var zxy = document.getElementById('zxy');
  var img = document.querySelector('img');
  // 2. 注册事件 处理程序
  zxy.onclick = function() {
    img.src = 'images/zxy.jpg';
    img.title = '张学友思密达';
  }
  ldh.onclick = function() {
    img.src = 'images/ldh.jpg';
    img.title = '刘德华';
  }
</script>
</body>

4.2.1. 案例:分时问候

image-20210802145255687

4.3 表单元素的属性操作

image-20210802145311553

获取属性的值

元素对象.属性名

设置属性的值

元素对象.属性名 = 值

表单元素中有⼀些属性如:disabled、checked、selected,元素对象的这些属性的值是布尔

型。

案例代码

<body><button>按钮</button>
<input type="text" value="输⼊内容"> <script>
  // 1. 获取元素
  var btn = document.querySelector('button');
  var input = document.querySelector('input');
  // 2. 注册事件 处理程序
  btn.onclick = function() {
// 表单⾥⾯的值 ⽂字内容是通过 value 来修改的
    input.value = '被点击了';
// 如果想要某个表单被禁⽤ 不能再点击 disabled 我们想要这个按钮
    button禁⽤
// btn.disabled = true;
    this.disabled = true;
// this 指向的是事件函数的调⽤者 btn
  }
</script>
</body>

4.3.1. 案例:仿京东显示密码

image-20210802145350380

4.4 样式属性操作

我们可以通过 JS 修改元素的⼤⼩、颜⾊、位置等样式。

常⽤⽅式

image-20210802145411488

4.4.1. ⽅式1:通过操作style属性

元素对象的style属性也是⼀个对象!

元素对象.style.样式属性 = 值;

image-20210802145427921

案例代码

<body><div></div>
<script>
  // 1. 获取元素
  var div = document.querySelector('div');
  // 2. 注册事件 处理程序
  div.onclick = function() {
// div.style⾥⾯的属性 采取驼峰命名法
    this.style.backgroundColor = 'purple';
    this.style.width = '250px';
  }
</script>
</body>

案例:淘宝点击关闭⼆维码

image-20210802145506899

image-20210802145519930

案例:显示隐藏⽂本框内容

image-20210802145537161

4.4.2. ⽅式2:通过操作className属性

元素对象.className = 值;

因为class是关键字,所有使⽤className。

image-20210802145556937

案例代码

<body><div class="first">⽂本</div>
<script>
  // 1. 使⽤ element.style 获得修改元素样式 如果样式⽐较少 或者 功能简单的
  情况下使⽤
var test = document.querySelector('div');
  test.onclick = function() {
// this.style.backgroundColor = 'purple';
// this.style.color = '#fff';
// this.style.fontSize = '25px';
// this.style.marginTop = '100px';
// 2. 我们可以通过 修改元素的className更改元素的样式 适合于样式较多或
    者功能复杂的情况
// 3. 如果想要保留原先的类名,我们可以这么做 多类名选择器
// this.className = 'change';
    this.className = 'first change';
  }
</script>
</body>

image-20210802145623145

4.5 ⼩结

image-20210802145655726

4.6. 排他操作

4.6.1. 排他思想

image-20210802145713496

如果有同⼀组元素,我们想要某⼀个元素实现某种样式, 需要⽤到循环的排他思想算法:

  1. 所有元素全部清除样式(⼲掉其他⼈)

  2. 给当前元素设置样式 (留下我⾃⼰)

  3. 注意顺序不能颠倒,⾸先⼲掉其他⼈,再设置⾃⼰

<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
// 1. 获取所有按钮元素
var btns = document.getElementsByTagName('button');
// btns得到的是伪数组 ⾥⾯的每⼀个元素 btns[i]
for (var i = 0; i < btns.length; i++) {
  btns[i].onclick = function() {
// (1) 我们先把所有的按钮背景颜⾊去掉 ⼲掉所有⼈
    for (var i = 0; i < btns.length; i++) {
      btns[i].style.backgroundColor = '';
    }
// (2) 然后才让当前的元素背景颜⾊为pink 留下我⾃⼰
    this.style.backgroundColor = 'pink';
  }
}
</script>

image-20210802145741115

image-20210802145748683

<body><ul class="baidu"> <li><img src="images/1.jpg"></li>
  <li><img src="images/2.jpg"></li>
  <li><img src="images/3.jpg"></li>
  <li><img src="images/4.jpg"></li>
</ul>
<script>
  // 1. 获取元素
  var imgs = document.querySelector('.baidu').querySelectorAll('img');
  // console.log(imgs);
  // 2. 循环注册事件
  for (var i = 0; i < imgs.length; i++) {
    imgs[i].onclick = function() {
// this.src 就是我们点击图⽚的路径 images/2.jpg
// console.log(this.src);
// 把这个路径 this.src 给body 就可以了
      document.body.style.backgroundImage = 'url(' + this.src +
        ')';
    }
  }
</script>
</body>

image-20210802145809724

image-20210802145817330

<script>
// 1. 全选和取消全选做法: 让下⾯所有复选框的checked属性(选中状态) 跟随
全选按钮即可
// 获取元素
var j_cbAll = document.getElementById('j_cbAll');
var j_tbs =
  document.getElementById('j_tb').getElementsByTagName('input');
// 全选按钮注册事件
j_cbAll.onclick = function() {
// this.checked 当前复选框的选中状态
  console.log(this.checked);
  for (var i = 0; i < j_tbs.length; i++) {
    j_tbs[i].checked = this.checked;
  }
}
// 给所有的⼦复选框注册单击事件
for (var i = 0; i < j_tbs.length; i++) {
  j_tbs[i].onclick = function() {
// flag 控制全选按钮是否选中
    var flag = true;
// 每次点击下⾯的复选框都要循环检查者4个⼩按钮是否全被选中
    for (var i = 0; i < j_tbs.length; i++) {
      if (!j_tbs[i].checked) {
        flag = false;
        break;
      }
    }
// 设置全选按钮的状态
    j_cbAll.checked = flag;
  }
}
</script>

案例:表格隔⾏变⾊

image-20210802145838321

<script>
// 1.获取元素 获取的是 tbody ⾥⾯所有的⾏
var trs = document.querySelector('tbody').querySelectorAll('tr');
// 2. 利⽤循环绑定注册事件
for (var i = 0; i < trs.length; i++) {
// 3. ⿏标经过事件 onmouseover
  trs[i].onmouseover = function() {
// console.log(11);
    this.className = 'bg';
  }
// 4. ⿏标离开事件 onmouseout
  trs[i].onmouseout = function() {
    this.className = '';
  }
}</script>

4.7. ⾃定义属性操作

4.7.1. 获取属性值

image-20210802145922099

<div id="demo" index="1" class="nav"></div>
<script>
var div = document.querySelector('div');
// 1. 获取元素的属性值
// (1) element.属性
console.log(div.id);
//(2) element.getAttribute('属性') get得到获取 attribute 属性的意思 我
们程序员⾃⼰添加的属性我们称为⾃定义属性 index
console.log(div.getAttribute('id'));
console.log(div.getAttribute('index'));
</script>

4.7.2. 设置属性值

image-20210802145942613

// 2. 设置元素属性值
// (1) element.属性= '值'
div.id = 'test';
div.className = 'navs';
// (2) element.setAttribute('属性', '值'); 主要针对于⾃定义属性
div.setAttribute('index', 2);
div.setAttribute('class', 'footer'); // class 特殊 这⾥⾯写的就是

4.7.3. 移出属性

image-20210802150010951

// class 不是className
// 3 移除属性 removeAttribute(属性)
div.removeAttribute('index');

案例:tab栏

image-20210802150047619

<script>
// 获取元素
var tab_list = document.querySelector('.tab_list');
var lis = tab_list.querySelectorAll('li');
var items = document.querySelectorAll('.item');
// for循环,给选项卡绑定点击事件
for (var i = 0; i < lis.length; i++) {
// 开始给5个⼩li 设置索引号
  lis[i].setAttribute('index', i);
  lis[i].onclick = function() {
// 1. 上的模块选项卡,当前这⼀个底⾊会是红⾊,其余不变(排他思想)
// ⼲掉所有⼈ 其余的li清除 class 这个类
    for (var i = 0; i < lis.length; i++) {
      lis[i].className = '';
    }
// 留下我⾃⼰
    this.className = 'current';
// 2. 下⾯的显示内容模块
    var index = this.getAttribute('index');
    console.log(index);
// ⼲掉所有⼈ 让其余的item 这些div 隐藏
    for (var i = 0; i < items.length; i++) {
      items[i].style.display = 'none';
    }
// 留下我⾃⼰ 让对应的item 显示出来
    items[index].style.display = 'block';
  }
}
</script>

4.8. H5⾃定义属性

⾃定义属性⽬的:是为了保存并使⽤数据。有些数据可以保存到⻚⾯中⽽不⽤保存到数据库中。

⾃定义属性获取是通过getAttribute(‘属性’) 获取。

但是有些⾃定义属性很容易引起歧义,不容易判断是元素的内置属性还是⾃定义属性。

H5给我们新增了⾃定义属性:

image-20210802150121307

<div getTime="20" data-index="2" data-list-name="andy"></div>
<script>
var div = document.querySelector('div');
// console.log(div.getTime);
console.log(div.getAttribute('getTime'));
div.setAttribute('data-time', 20);
console.log(div.getAttribute('data-index'));
console.log(div.getAttribute('data-list-name'));
// h5新增的获取⾃定义属性的⽅法 它只能获取data-开头的
// dataset 是⼀个集合⾥⾯存放了所有以data开头的⾃定义属性
console.log(div.dataset);
console.log(div.dataset.index);
console.log(div.dataset['index']);
// 如果⾃定义属性⾥⾯有多个-链接的单词,我们获取的时候采取 驼峰命名法
console.log(div.dataset.listName);
console.log(div.dataset['listName']);
</script>

5 - 节点操作

5.1. 节点概述

⽹⻚中的所有内容都是节点(标签、属性、⽂本、注释等),在DOM 中,节点使⽤ node 来表示。

HTML DOM 树中的所有节点均可通过 JavaScript 进⾏访问,所有 HTML 元素(节点)均可被修改,也

可以创建或删除。

image-20210802150200349

⼀般地,节点⾄少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)

这三个基本属性。

image-20210802150214314

5.2. 节点层级

利⽤ DOM 树可以把节点划分为不同的层级关系,常⻅的是⽗⼦兄层级关系

image-20210802150230918

5.3. ⽗级节点

image-20210802150257054

<div class="demo"> <div class="box"> <span class="erweima">×</span>
</div>
</div>
<script>
// 1. ⽗节点 parentNode
var erweima = document.querySelector('.erweima');
// var box = document.querySelector('.box');
// 得到的是离元素最近的⽗级节点(亲爸爸) 如果找不到⽗节点就返回为 null
console.log(erweima.parentNode);
</script>

5.4. ⼦节点

所有⼦节点

image-20210802150317091

⼦元素节点

image-20210802150327906

<ul><li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
<script>
// DOM 提供的⽅法(API)获取
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
// 1. ⼦节点 childNodes 所有的⼦节点 包含 元素节点 ⽂本节点等等
console.log(ul.childNodes);
console.log(ul.childNodes[0].nodeType);
console.log(ul.childNodes[1].nodeType);
// 2. children 获取所有的⼦元素节点 也是我们实际开发常⽤的
console.log(ul.children);
</script>

1个⼦节点

image-20210802150441016

最后1个⼦节点

image-20210802150449785

1个⼦元素节点

image-20210802150459257

最后1个⼦元素节点

image-20210802150516039

实际开发中, firstChild 和 lastChild 包含其他节点,操作不⽅便,⽽ firstElementChild 和

lastElementChild ⼜有兼容性问题,那么我们如何获取第⼀个⼦元素节点或最后⼀个⼦元素节点呢?

image-20210802150531281

<ol> <li>我是li1</li>
<li>我是li2</li>
<li>我是li3</li>
<li>我是li4</li>
<li>我是li5</li>
</ol>
<script>
var ol = document.querySelector('ol');
// 1. firstChild 第⼀个⼦节点 不管是⽂本节点还是元素节点
console.log(ol.firstChild);
console.log(ol.lastChild);
// 2. firstElementChild 返回第⼀个⼦元素节点 ie9才⽀持
console.log(ol.firstElementChild);
console.log(ol.lastElementChild);
// 3. 实际开发的写法 既没有兼容性问题⼜返回第⼀个⼦元素
console.log(ol.children[0]);
console.log(ol.children[ol.children.length - 1]);
</script>
案例:新浪下拉菜单

image-20210802150555152

image-20210802150612483

<script>
// 1. 获取元素
var nav = document.querySelector('.nav');
var lis = nav.children; // 得到4个⼩li
// 2.循环注册事件
for (var i = 0; i < lis.length; i++) {
  lis[i].onmouseover = function() {
    this.children[1].style.display = 'block';
  }
  lis[i].onmouseout = function() {
    this.children[1].style.display = 'none';
  }
}
</script>

5.5. 兄弟节点

下⼀个兄弟节点

image-20210802150636045

上⼀个兄弟节点

image-20210802150644185

<div>我是div</div>
<span>我是span</span>
<script>
var div = document.querySelector('div');
// 1.nextSibling 下⼀个兄弟节点 包含元素节点或者 ⽂本节点等等
console.log(div.nextSibling);
console.log(div.previousSibling);
// 2. nextElementSibling 得到下⼀个兄弟元素节点
console.log(div.nextElementSibling);
console.log(div.previousElementSibling);
</script>

下⼀个兄弟元素节点(有兼容性问题)

image-20210802150709271

上⼀个兄弟元素节点(有兼容性问题)

image-20210802150730866

function getNextElementSibling(element) {
var el = element;
while (el = el.nextSibling) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}

5.6. 创建节点

image-20210802150754614

5.7. 添加节点

image-20210802150806407

<ul><li>123</li>
</ul>
<script>
// 1. 创建节点元素节点
var li = document.createElement('li');
// 2. 添加节点 node.appendChild(child) node ⽗级 child 是⼦级 后⾯追加
元素
var ul = document.querySelector('ul');
ul.appendChild(li);
// 3. 添加节点 node.insertBefore(child, 指定元素);
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]);
// 4. 我们想要⻚⾯添加⼀个新的元素 : 1. 创建元素 2. 添加元素
</script>

案例:简单版发布留⾔

image-20210802150832453

image-20210802150838123

<body><textarea name="" id=""></textarea>
<button>发布</button>
<ul> </ul>
<script>
  // 1. 获取元素
  var btn = document.querySelector('button');
  var text = document.querySelector('textarea');
  var ul = document.querySelector('ul');
  // 2. 注册事件
  btn.onclick = function() {
    if (text.value == '') {
      alert('您没有输⼊内容');
      return false;
    } else {
// console.log(text.value);
// (1) 创建元素
      var li = document.createElement('li');
// 先有li 才能赋值
      li.innerHTML = text.value;
// (2) 添加元素
// ul.appendChild(li);
      ul.insertBefore(li, ul.children[0]);
    }
  }
</script>
</body>

5.8. 删除节点

image-20210802150859801

<button>删除</button>
<ul><li>熊⼤</li>
<li>熊⼆</li>
<li>光头强</li>
</ul>
<script>
// 1.获取元素
var ul = document.querySelector('ul');
var btn = document.querySelector('button');
// 2. 删除元素 node.removeChild(child)
// ul.removeChild(ul.children[0]);
// 3. 点击按钮依次删除⾥⾯的孩⼦
btn.onclick = function() {
  if (ul.children.length == 0) {
    this.disabled = true;
  } else {
    ul.removeChild(ul.children[0]);
  }
}
</script>

案例:删除留⾔

image-20210802150949733

image-20210802151004105

<textarea name="" id=""></textarea>
<button>发布</button>
<ul> </ul>
<script>
// 1. 获取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
// 2. 注册事件
btn.onclick = function() {
  if (text.value == '') {
    alert('您没有输⼊内容');
    return false;
  } else {
// console.log(text.value);
// (1) 创建元素
    var li = document.createElement('li');
// 先有li 才能赋值
    li.innerHTML = text.value + "<a href='javascript:;'>删除</a>";
// (2) 添加元素
// ul.appendChild(li);
    ul.insertBefore(li, ul.children[0]);
// (3) 删除元素 删除的是当前链接的li 它的⽗亲
    var as = document.querySelectorAll('a');
    for (var i = 0; i < as.length; i++) {
      as[i].onclick = function() {
// 删除的是 li 当前a所在的li this.parentNode;
        ul.removeChild(this.parentNode);
      }
    }
  }
}
</script>

5.9. 复制(克隆)节点

image-20210802151042298

<ul><li>1111</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ul = document.querySelector('ul');
// 1. node.cloneNode(); 括号为空或者⾥⾯是false 浅拷⻉ 只复制标签不复制⾥
⾯的内容
// 2. node.cloneNode(true); 括号为true 深拷⻉ 复制标签复制⾥⾯的内容
var lili = ul.children[0].cloneNode(true);
ul.appendChild(lili);
</script>

案例:动态⽣成表格

image-20210802151111032

<script>
// 1.先去准备好学⽣的数据
var datas = [{
  name: '魏璎珞',
  subject: 'JavaScript',
  score: 100
}, {
  name: '弘历',
  subject: 'JavaScript',
  score: 98
}, {
  name: '傅恒',
  subject: 'JavaScript',
  score: 99
}, {
  name: '明⽟',
  subject: 'JavaScript',
  score: 88
}, {
  name: '⼤猪蹄⼦',
  subject: 'JavaScript',
  score: 0
}];
// 2. 往tbody ⾥⾯创建⾏: 有⼏个⼈(通过数组的⻓度)我们就创建⼏⾏
var tbody = document.querySelector('tbody');
// 遍历数组
for (var i = 0; i < datas.length; i++) {
// 1. 创建 tr⾏
  var tr = document.createElement('tr');
  tbody.appendChild(tr);
// 2. ⾏⾥⾯创建单元格td 单元格的数量取决于每个对象⾥⾯的属性个数
// 使⽤for in遍历学⽣对象
  for (var k in datas[i]) {
// 创建单元格
    var td = document.createElement('td');
// 把对象⾥⾯的属性值 datas[i][k] 给 td 
    td.innerHTML = datas[i][k];
    tr.appendChild(td);
  }
// 3. 创建有删除2个字的单元格
  var td = document.createElement('td');
  td.innerHTML = '<a href="javascript:;">删除 </a>';
  tr.appendChild(td);
}
// 4. 删除操作 开始
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
  as[i].onclick = function() {
// 点击a 删除 当前a 所在的⾏(链接的爸爸的爸爸)
    node.removeChild(child)
    tbody.removeChild(this.parentNode.parentNode)
  }
}
</script>

5.10. 创建元素的三种⽅式

image-20210802151142676

<script>
// 三种创建元素⽅式区别
// 1. document.write() 创建元素 如果⻚⾯⽂档流加载完毕,再调⽤这句话会导
致⻚⾯重绘
var btn = document.querySelector('button');
btn.onclick = function() {
  document.write('<div>123</div>');
}
// 2. innerHTML 创建元素
var inner = document.querySelector('.inner');
for (var i = 0; i <= 100; i++) {
  inner.innerHTML += '<a href="#">百度</a>'
}
var arr = [];
for (var i = 0; i <= 100; i++) {
  arr.push('<a href="#">百度</a>');
}
inner.innerHTML = arr.join('');
// 3. document.createElement() 创建元素
var create = document.querySelector('.create');
for (var i = 0; i <= 100; i++) {
  var a = document.createElement('a');
  create.appendChild(a);
}
</script>

5.11. innerTHML和createElement效率对⽐

innerHTML字符串拼接⽅式(效率低)

<script>
function fn() {
  var d1 = +new Date();
  var str = '';
  for (var i = 0; i < 1000; i++) {
    document.body.innerHTML += '<div style="100px; height:2px;
    border:1px solid blue;"></div>';
  }
  var d2 = +new Date();
  console.log(d2 - d1);
}
fn();
</script>

createElement⽅式(效率⼀般)

<script>
function fn() {
  var d1 = +new Date();
  for (var i = 0; i < 1000; i++) {
    var div = document.createElement('div');
    div.style.width = '100px';
    div.style.height = '2px';
    div.style.border = '1px solid red';
    document.body.appendChild(div);
  }
  var d2 = +new Date();
  console.log(d2 - d1);
}
fn();
</script>

innerHTML数组⽅式(效率⾼)

<script>
function fn() {
  var d1 = +new Date();
  var array = [];
  for (var i = 0; i < 1000; i++) {
    array.push('<div style="100px; height:2px; border:1px solid
    blue;"></div>');
  }
  document.body.innerHTML = array.join('');
  var d2 = +new Date();
  console.log(d2 - d1);
}
fn();
</script>

6 - DOM的核⼼总结

image-20210802151245414

6.1. 创建

image-20210802151325257

6.2. 增加

image-20210802151334592

6.3. 删

image-20210802151342273

6.4. 改

image-20210802151350050

6.5. 查

image-20210802151419414

6.6. 属性操作

image-20210802151429249

7 - 事件⾼级

7.1. 注册事件(2种⽅式)

image-20210802151508827

7.2 事件监听

addEventListener()事件监听(IE9以后⽀持)

image-20210802151527863

eventTarget.addEventListener()⽅法将指定的监听器注册到 eventTarget(⽬标对象)上,当该对象

触发指定的事件时,就会执⾏事件处理函数。

image-20210802151539018

attacheEvent()事件监听(IE678⽀持)

image-20210802151550023

eventTarget.attachEvent()⽅法将指定的监听器注册到 eventTarget(⽬标对象) 上,当该对象触发

指定的事件时,指定的回调函数就会被执⾏。

image-20210802151605939

<button>传统注册事件</button>
<button>⽅法监听注册事件</button>
<button>ie9 attachEvent</button>
<script>
var btns = document.querySelectorAll('button');
// 1. 传统⽅式注册事件
btns[0].onclick = function() {
  alert('hi');
}
btns[0].onclick = function() {
  alert('hao a u');
}
// 2. 事件侦听注册事件 addEventListener
// (1) ⾥⾯的事件类型是字符串 必定加引号 ⽽且不带on
// (2) 同⼀个元素 同⼀个事件可以添加多个侦听器(事件处理程序)
btns[1].addEventListener('click', function() {
  alert(22);
})
btns[1].addEventListener('click', function() {
  alert(33);
})
// 3. attachEvent ie9以前的版本⽀持
btns[2].attachEvent('onclick', function() {
  alert(11);
})
</script>

事件监听兼容性解决⽅案

封装⼀个函数,函数中判断浏览器的类型:

image-20210802151629776

7.3. 删除事件(解绑事件)

image-20210802151645218

<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function() {
  alert(11);
// 1. 传统⽅式删除事件
  divs[0].onclick = null;
}
// 2. removeEventListener 删除事件
divs[1].addEventListener('click', fn) // ⾥⾯的fn 不需要调⽤加⼩括号
function fn() {
  alert(22);
  divs[1].removeEventListener('click', fn);
}
// 3. detachEvent
divs[2].attachEvent('onclick', fn1);
function fn1() {
  alert(33);
  divs[2].detachEvent('onclick', fn1);
}
</script>

删除事件兼容性解决⽅案

image-20210802151709899

7.4. DOM事件流

html中的标签都是相互嵌套的,我们可以将元素想象成⼀个盒⼦装⼀个盒⼦,document是
最外⾯的⼤盒⼦。
当你单击⼀个div时,同时你也单击了div的⽗元素,甚⾄整个⻚⾯。
那么是先执⾏⽗元素的单击事件,还是先执⾏div的单击事件 ???

image-20210802151735004

⽐如:我们给⻚⾯中的⼀个div注册了单击事件,当你单击了div时,也就单击了body,单击了html,单击了document。

image-20210802151747331

image-20210802151756560

当时的2⼤浏览器霸主谁也不服谁!
IE 提出从⽬标元素开始,然后⼀层⼀层向外接收事件并响应,也就是冒泡型事件流。
Netscape(⽹景公司)提出从最外层开始,然后⼀层⼀层向内接收事件并响应,也就是捕获
型事件流。
江湖纷争,武林盟主也脑壳疼!!!
最终,w3c 采⽤折中的⽅式,平息了战⽕,制定了统⼀的标准 —--— 先捕获再冒泡。
现代浏览器都遵循了此标准,所以当事件发⽣时,会经历3个阶段。

DOM 事件流会经历3个阶段:

  1. 捕获阶段

  2. 当前⽬标阶段

  3. 冒泡阶段

我们向⽔⾥⾯扔⼀块⽯头,⾸先它会有⼀个下降的过程,这个过程就可以理解为从最顶层向事件发⽣的

最具体元素(⽬标点)的捕获过程;之后会产⽣泡泡,会在最低点( 最具体元素)之后漂浮到⽔⾯上,

这个过程相当于事件冒泡。

image-20210802151844717

image-20210802151853131

事件冒泡

<div class="father"> <div class="son">son盒⼦</div>
</div>
<script>
// onclick 和 attachEvent(ie) 在冒泡阶段触发
// 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略
// son -> father ->body -> html -> document
var son = document.querySelector('.son');
// 给son注册单击事件
son.addEventListener('click', function() {
  alert('son');
}, false);
// 给father注册单击事件
var father = document.querySelector('.father');
father.addEventListener('click', function() {
  alert('father');
}, false);
// 给document注册单击事件,省略第3个参数
document.addEventListener('click', function() {
  alert('document');
})
</script>

事件捕获

<div class="father"> <div class="son">son盒⼦</div>
</div>
<script>
// 如果addEventListener() 第三个参数是 true 那么在捕获阶段触发
// document -> html -> body -> father -> son
var son = document.querySelector('.son');
// 给son注册单击事件,第3个参数为true
son.addEventListener('click', function() {
  alert('son');
}, true);
var father = document.querySelector('.father');
// 给father注册单击事件,第3个参数为true
father.addEventListener('click', function() {
  alert('father');
}, true);
// 给document注册单击事件,第3个参数为true
document.addEventListener('click', function() {
  alert('document');
}, true) </script>

7.5. 事件对象

什么是事件对象

事件发⽣后,跟事件相关的⼀系列信息数据的集合都放到这个对象⾥⾯,这个对象就是事件对象。

⽐如:

  1. 谁绑定了这个事件。

  2. ⿏标触发事件的话,会得到⿏标的相关信息,如⿏标位置。

  3. 键盘触发事件的话,会得到键盘的相关信息,如按了哪个键。

事件对象的使⽤

事件触发发⽣时就会产⽣事件对象,并且系统会以实参的形式传给事件处理函数。所以,在事件处理函数中声明1个形参⽤来接收事件对象。

image-20210802151949863

事件对象的兼容性处理

事件对象本身的获取存在兼容问题:

  1. 标准浏览器中是浏览器给⽅法传递的参数,只需要定义形参 e 就可以获取到。

  2. 在 IE6~8 中,浏览器不会给⽅法传递参数,如果需要的话,需要到 window.event 中获取查找。

image-20210802152009485

只要“||”前⾯为false, 不管“||”后⾯是true 还是 false,都返回 “||” 后⾯的值。
只要“||”前⾯为true, 不管“||”后⾯是true 还是 false,都返回 “||” 前⾯的值。
<div>123</div>
<script>
var div = document.querySelector('div');
div.onclick = function(e) {
// 事件对象
  e = e || window.event;
  console.log(e);
}
</script>

事件对象的属性和⽅法

image-20210802152034147

e.target 和 this 的区别

  • this 是事件绑定的元素(绑定这个事件处理函数的元素) 。

  • e.target 是事件触发的元素。

    常情况下terget 和 this是⼀致的, 但有⼀种情况不同,那就是在事件冒泡时(⽗⼦元素有相同事
    件,单击⼦元素,⽗元素的事件处理函数也会被触发执⾏), 这时候this指向的是⽗元素,因为它
    是绑定事件的元素对象, ⽽target指向的是⼦元素,因为他是触发事件的那个具体元素对象。
    
<div>123</div>
<script>
var div = document.querySelector('div');
div.addEventListener('click', function(e) {
// e.target 和 this指向的都是div
  console.log(e.target);
  console.log(this);
});
</script>

事件冒泡下的e.target和this

<ul><li>abc</li>
<li>abc</li>
<li>abc</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// 我们给ul 绑定了事件 那么this 就指向ul 
  console.log(this); // ul
// e.target 触发了事件的对象 我们点击的是li e.target 指向的就是li
  console.log(e.target); // li
});
</script>

7.6 阻⽌默认⾏为

html中⼀些标签有默认⾏为,例如a标签被单击后,默认会进⾏⻚⾯跳转。

href="javacript:void(0);"

<a href="http://www.baidu.com">百度</a>
<script>
// 2. 阻⽌默认⾏为 让链接不跳转
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
  e.preventDefault(); // dom 标准写法
});
// 3. 传统的注册⽅式
a.onclick = function(e) {
// 普通浏览器 e.preventDefault(); ⽅法
  e.preventDefault();
// 低版本浏览器 ie678 returnValue 属性
  e.returnValue = false;
// 我们可以利⽤return false 也能阻⽌默认⾏为 没有兼容性问题
  return false;
}
</script>

7.7 阻⽌事件冒泡

事件冒泡本身的特性,会带来的坏处,也会带来的好处。

image-20210802152216247

<div class="father"> <div class="son">son⼉⼦</div>
</div>
<script>
var son = document.querySelector('.son');
// 给son注册单击事件
son.addEventListener('click', function(e) {
  alert('son');
  e.stopPropagation(); // stop 停⽌ Propagation 传播
  window.event.cancelBubble = true; // ⾮标准 cancel 取消 bubble 泡 泡
}, false);
var father = document.querySelector('.father');
// 给father注册单击事件
father.addEventListener('click', function() {
  alert('father');
}, false);
// 给document注册单击事件
document.addEventListener('click', function() {
  alert('document');
})
</script>

阻⽌事件冒泡的兼容性处理

image-20210802152234017

7.8 事件委托

事件冒泡本身的特性,会带来的坏处,也会带来的好处。

什么是事件委托

把事情委托给别⼈,代为处理。

事件委托也称为事件代理,在 jQuery ⾥⾯称为事件委派。

说⽩了就是,不给⼦元素注册事件,给⽗元素注册事件,把处理代码在⽗元素的事件中执⾏。

⽣活中的代理:

image-20210802152251578

js事件中的代理:

image-20210802152317580

事件委托的原理

给⽗元素注册事件,利⽤事件冒泡,当⼦元素的事件触发,会冒泡到⽗元素,然后去控制相应的⼦元素。

事件委托的作⽤

  • 我们只操作了⼀次 DOM ,提⾼了程序的性能。
  • 动态新创建的⼦元素,也拥有事件。
<ul><li>知否知否,点我应有弹框在⼿!</li>
<li>知否知否,点我应有弹框在⼿!</li>
<li>知否知否,点我应有弹框在⼿!</li>
<li>知否知否,点我应有弹框在⼿!</li>
<li>知否知否,点我应有弹框在⼿!</li>
</ul>
<script>
// 事件委托的核⼼原理:给⽗节点添加侦听器, 利⽤事件冒泡影响每⼀个⼦节点
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// e.target 这个可以得到我们点击的对象
  e.target.style.backgroundColor = 'pink';
})
</script>

8 - 常⽤⿏标事件

image-20210802152356059

8.1 mouseenter 和mouseover的区别

  • 当⿏标移动到元素上时就会触发mouseenter 事件
  • 类似 mouseover,它们两者之间的差别是
  • mouseover ⿏标经过⾃身盒⼦会触发,经过⼦盒⼦还会触发。mouseenter 只会经过⾃身盒⼦触发
  • 之所以这样,就是因为mouseenter不会冒泡
  • 跟mouseenter搭配⿏标离开 mouseleave 同样不会冒泡

8.2 禁⽌选中⽂字和禁⽌右键菜单

image-20210802152429547

<body>
我是⼀段不愿意分享的⽂字
<script>
  // 1. contextmenu 我们可以禁⽤右键菜单
  document.addEventListener('contextmenu', function(e) {
    e.preventDefault();
  })
  // 2. 禁⽌选中⽂字 selectstart
  document.addEventListener('selectstart', function(e) {
    e.preventDefault();
  })
</script>
</body>

8.3 ⿏标事件对象

image-20210802152450570

8.4 获取⿏标在⻚⾯的坐标

<script>
// ⿏标事件对象 MouseEvent
document.addEventListener('click', function(e) {
// 1. client ⿏标在可视区的x和y坐标
  console.log(e.clientX);
  console.log(e.clientY);
  console.log('---------------------');
// 2. page ⿏标在⻚⾯⽂档的x和y坐标
  console.log(e.pageX);
  console.log(e.pageY);
  console.log('---------------------');
// 3. screen ⿏标在电脑屏幕的x和y坐标
  console.log(e.screenX);
  console.log(e.screenY);
})
</script>

image-20210802152520056

<img src="images/angel.gif" alt=""> <script>
var pic = document.querySelector('img');
document.addEventListener('mousemove', function(e) {
// 1. mousemove只要我们⿏标移动1px 就会触发这个事件
// 2.核⼼原理: 每次⿏标移动,我们都会获得最新的⿏标坐标,
// 把这个x和y坐标做为图⽚的top和left 值就可以移动图⽚
  var x = e.pageX;
  var y = e.pageY;
  console.log('x坐标是' + x, 'y坐标是' + y);
//3 . 千万不要忘记给left 和top 添加px 单位
  pic.style.left = x - 50 + 'px';
  pic.style.top = y - 40 + 'px';
});
</script>

9 - 常⽤的键盘事件

9.1 键盘事件

image-20210802152549636

<script>
// 常⽤的键盘事件
//1. keyup 按键弹起的时候触发
document.addEventListener('keyup', function() {
  console.log('我弹起了');
})
//3. keypress 按键按下的时候触发 不能识别功能键 ⽐如 ctrl shift 左右箭头
啊
document.addEventListener('keypress', function() {
  console.log('我按下了press');
})
//2. keydown 按键按下的时候触发 能识别功能键 ⽐如 ctrl shift 左右箭头啊
document.addEventListener('keydown', function() {
  console.log('我按下了down');
})
// 4. 三个事件的执⾏顺序 keydown -- keypress -- keyup
</script>

9.2 键盘事件对象

image-20210802152613504

image-20210802152622234

使⽤keyCode属性判断⽤户按下哪个键

<script>
// 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
document.addEventListener('keyup', function(e) {
  console.log('up:' + e.keyCode);
// 我们可以利⽤keycode返回的ASCII码值来判断⽤户按下了那个键
  if (e.keyCode === 65) {
    alert('您按下的a键');
  } else {
    alert('您没有按下a键')
  }
})
document.addEventListener('keypress', function(e) {
// console.log(e);
  console.log('press:' + e.keyCode);
})
</script>

案例:模拟京东按键输⼊内容

当我们按下 s 键, 光标就定位到搜索框(⽂本框获得焦点)。

image-20210802152647186

<input type="text"> <script>
// 获取输⼊框
var search = document.querySelector('input');
// 给document注册keyup事件
document.addEventListener('keyup', function(e) {
// 判断keyCode的值
  if (e.keyCode === 83) {
// 触发输⼊框的获得焦点事件
    search.focus();
  }
})
</script>

案例:模拟京东快递单号查询

要求:当我们在⽂本框中输⼊内容时,⽂本框上⾯⾃动显示⼤字号的内容。

image-20210802152720117

<div class="search"> <div class="con">123</div>
<input type="text" placeholder="请输⼊您的快递单号" class="jd"> </div>
<script>
// 获取要操作的元素
var con = document.querySelector('.con');
var jd_input = document.querySelector('.jd');
// 给输⼊框注册keyup事件
jd_input.addEventListener('keyup', function() {
// 判断输⼊框内容是否为空
  if (this.value == '') {
// 为空,隐藏放⼤提示盒⼦
    con.style.display = 'none';
  } else {
// 不为空,显示放⼤提示盒⼦,设置盒⼦的内容
    con.style.display = 'block';
    con.innerText = this.value;
  }
})
// 给输⼊框注册失去焦点事件,隐藏放⼤提示盒⼦
jd_input.addEventListener('blur', function() {
  con.style.display = 'none';
})
// 给输⼊框注册获得焦点事件
jd_input.addEventListener('focus', function() {
// 判断输⼊框内容是否为空
  if (this.value !== '') {
// 不为空则显示提示盒⼦
    con.style.display = 'block';
  }
})
</script>

10 - BOM

10.1. 什么是BOM

BOM(Browser Object Model)即浏览器对象模型,它提供了独⽴于内容⽽与浏览器窗⼝进⾏交互的对象,其核⼼对象是 window。

BOM 由⼀系列相关的对象构成,并且每个对象都提供了很多⽅法与属性。

BOM 缺乏标准,JavaScript 语法的标准化组织是 ECMA,DOM 的标准化组织是 W3C,BOM 最初是Netscape 浏览器标准的⼀部分。

image-20210802152802581

10.2. BOM的构成

BOM ⽐ DOM 更⼤,它包含 DOM。

image-20210802152815977

10.3. 顶级对象window

image-20210802152830705

10.4. window对象的常⻅事件

⻚⾯(窗⼝)加载事件(3种)

1

image-20210802152842554

window.onload 是窗⼝ (⻚⾯)加载事件,当⽂档内容完全加载完成会触发该事件(包括图像、脚本⽂

件、CSS ⽂件等), 就调⽤的处理函数。

image-20210802152853522

2

image-20210802152907416

DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图⽚,flash等等。

IE9以上才⽀持!!!

如果⻚⾯的图⽚很多的话, 从⽤户访问到onload触发可能需要较⻓的时间, 交互效果就不能实现,必然影响⽤户的体验,此时⽤ DOMContentLoaded 事件⽐较合适。

<script>
window.addEventListener('load', function() {
  var btn = document.querySelector('button');
  btn.addEventListener('click', function() {
    alert('点击我');
  })
})
window.addEventListener('load', function() {
  alert(22);
})
document.addEventListener('DOMContentLoaded', function() {
  alert(33);
})
</script>

3

pageshow 事件,事件在⽤户浏览⽹⻚时触发。onpageshow 事件类似于 onload 事件,onload 事件在⻚⾯第⼀次加载时触发, onpageshow 事件在每次加载⻚⾯时触发,即 onload 事件在⻚⾯从浏览器缓存中读取时不触发。

调整窗⼝⼤⼩事件

image-20210802152951728

window.onresize 是调整窗⼝⼤⼩加载事件, 当触发时就调⽤的处理函数。

注意:

  1. 只要窗⼝⼤⼩发⽣像素变化,就会触发这个事件。

  2. 我们经常利⽤这个事件完成响应式布局。 window.innerWidth 当前屏幕的宽度

<script>
// 注册⻚⾯加载事件
window.addEventListener('load', function() {
  var div = document.querySelector('div');
// 注册调整窗⼝⼤⼩事件
  window.addEventListener('resize', function() {
// window.innerWidth 获取窗⼝⼤⼩
    console.log('变化了');
    if (window.innerWidth <= 800) {
      div.style.display = 'none';
    } else {
      div.style.display = 'block';
    }
  })
})
</script>
<div></div>

10.5. 定时器(两种)

window 对象给我们提供了 2 个⾮常好⽤的⽅法-定时器。

  • setTimeout()
  • setInterval()

setTimeout() 炸弹定时器

开启定时器

image-20210802153056318

image-20210802153106725

普通函数是按照代码顺序直接调⽤。
简单理解: 回调,就是回头调⽤的意思。上⼀件事⼲完,再回头再调⽤这个函数。
例如:定时器中的调⽤函数,事件处理函数,也是回调函数。
以前我们讲的 element.onclick = function(){} 或者
element.addEventListener(“click”, fn); ⾥⾯的 函数也是回调函数。
<script>
// 回调函数是⼀个匿名函数
setTimeout(function() {
  console.log('时间到了');
}, 2000);
function callback() {
  console.log('爆炸了');
}
// 回调函数是⼀个有名函数
var timer1 = setTimeout(callback, 3000);
var timer2 = setTimeout(callback, 5000);
</script>

案例:5秒后关闭⼴告

image-20210802153132576

image-20210802153139556

<body><img src="images/ad.jpg" alt="" class="ad"> <script>
  // 获取要操作的元素
  var ad = document.querySelector('.ad');
  // 开启定时器
  setTimeout(function() {
    ad.style.display = 'none';
  }, 5000);
</script>
</body>

停⽌定时器

image-20210802153155628

<button>点击停⽌定时器</button>
<script>
var btn = document.querySelector('button');
// 开启定时器
var timer = setTimeout(function() {
  console.log('爆炸了');
}, 5000);
// 给按钮注册单击事件
btn.addEventListener('click', function() {
// 停⽌定时器
  clearTimeout(timer);
})
</script>

setInterval() 闹钟定时器

开启定时器

image-20210802153218592

<script>
// 1. setInterval
setInterval(function() {
  console.log('继续输出');
}, 1000);
</script>

案例:倒计时

image-20210802153242580

image-20210802153250581

<div><span class="hour">1</span>
<span class="minute">2</span>
<span class="second">3</span>
</div>
<script>
// 1. 获取元素(时分秒盒⼦)
var hour = document.querySelector('.hour'); // ⼩时的⿊⾊盒⼦
var minute = document.querySelector('.minute'); // 分钟的⿊⾊盒⼦
var second = document.querySelector('.second'); // 秒数的⿊⾊盒⼦
var inputTime = +new Date('2019-5-1 18:00:00'); // 返回的是⽤户输⼊时间
总的毫秒数
countDown(); // 我们先调⽤⼀次这个函数,防⽌第⼀次刷新⻚⾯有空⽩
// 2. 开启定时器
setInterval(countDown, 1000);
function countDown() {
  var nowTime = +new Date(); // 返回的是当前时间总的毫秒数
  var times = (inputTime - nowTime) / 1000; // times是剩余时间总的秒
  数
  var h = parseInt(times / 60 / 60 % 24); //时 h = h < 10 ? '0' + h : h;
  hour.innerHTML = h; // 把剩余的⼩时给 ⼩时⿊⾊盒⼦
  var m = parseInt(times / 60 % 60); // 分 m = m < 10 ? '0' + m : m;
  minute.innerHTML = m;
  var s = parseInt(times % 60); // 当前的秒
  s = s < 10 ? '0' + s : s;
  second.innerHTML = s;
}
</script>

停⽌定时器

image-20210802153312558

案例:发送短信倒计时

点击按钮后,该按钮60秒之内不能再次点击,防⽌重复发送短信。

image-20210802153335113

⼿机号码: <input type="number"> <button>发送</button>
<script>
var btn = document.querySelector('button');
// 全局变量,定义剩下的秒数
var time = 3;
// 注册单击事件
btn.addEventListener('click', function() {
// 禁⽤按钮
  btn.disabled = true;
// 开启定时器
  var timer = setInterval(function() {
// 判断剩余秒数
    if (time == 0) {
// 清除定时器和复原按钮
      clearInterval(timer);
      btn.disabled = false;
      btn.innerHTML = '发送';
    } else {
      btn.innerHTML = '还剩下' + time + '秒';
      time--;
    }
  }, 1000);
});
</script>

10.6. this指向问题

this的指向在函数定义的时候是确定不了的,只有函数执⾏的时候才能确定this到底指向谁,⼀般情况下this的最终指向的是那个调⽤它的对象。

现阶段,我们先了解⼀下⼏个this指向

  1. 全局作⽤域或者普通函数中this指向全局对象window(注意定时器⾥⾯的this指向window)

  2. ⽅法调⽤中谁调⽤this指向谁

  3. 构造函数中this指向构造函数的实例

<button>点击</button>
<script>
// this 指向问题 ⼀般情况下this的最终指向的是那个调⽤它的对象
// 1. 全局作⽤域或者普通函数中this指向全局对象window( 注意定时器⾥⾯的
this指向window)
console.log(this);
function fn() {
  console.log(this);
}
window.fn();
window.setTimeout(function() {
  console.log(this);
}, 1000);
// 2. ⽅法调⽤中谁调⽤this指向谁
var o = {
  sayHi: function() {
    console.log(this); // this指向的是 o 这个对象
  }
}
o.sayHi();
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
  console.log(this); // 事件处理函数中的this指向的是btn这个按钮对
  象
})
// 3. 构造函数中this指向构造函数的实例
function Fun() {
  console.log(this); // this 指向的是fun 实例对象
}
var fun = new Fun();
</script>

10.7. location对象

什么是 location 对象

image-20210802153439178

URL

image-20210802153449478

location 对象的属性

image-20210802153519728

案例:5分钟⾃动跳转⻚⾯

image-20210802153534573

<button>点击</button>
<div></div>
<script>
var btn = document.querySelector('button');
var div = document.querySelector('div');
btn.addEventListener('click', function() {
// console.log(location.href);
  location.href = 'http://www.itcast.cn';
})
var timer = 5;
setInterval(function() {
  if (timer == 0) {
    location.href = 'http://www.itcast.cn';
  } else {
    div.innerHTML = '您将在' + timer + '秒钟之后跳转到⾸⻚';
    timer--;
  }
}, 1000);
</script>

案例:获取URL参数

image-20210802153602815

<div></div>
<script>
console.log(location.search); // ?uname=andy
// 1.先去掉? substr('起始的位置',截取⼏个字符);
var params = location.search.substr(1); // uname=andy
console.log(params);
// 2. 利⽤=把字符串分割为数组 split('=');
var arr = params.split('=');
console.log(arr); // ["uname", "ANDY"]
var div = document.querySelector('div');
// 3.把数据写⼊div中
div.innerHTML = arr[1] + '欢迎您'; </script>

location对象的常⻅⽅法

image-20210802153633506

<button>点击</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// 记录浏览历史,所以可以实现后退功能
// location.assign('http://www.itcast.cn');
// 不记录浏览历史,所以不可以实现后退功能
// location.replace('http://www.itcast.cn');
  location.reload(true);
})
</script>

10.8. navigator对象

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

下⾯前端代码可以判断⽤户那个终端打开⻚⾯,实现跳转

if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mo
bile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Sym
bian|Windows Phone)/i))) {
window.location.href = ""; //⼿机
} else {
window.location.href = ""; //电脑
}

10.9 history对象

window对象给我们提供了⼀个 history对象,与浏览器历史记录进⾏交互。该对象包含⽤户(在浏览器

窗⼝中)访问过的URL。

image-20210802154807050

history对象⼀般在实际开发中⽐较少⽤,但是会在⼀些 OA 办公系统中⻅到。

image-20210802154821218

11 - JS执⾏机制

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

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

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

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

11.1 JS 是单线程

image-20210802154928122

单线程就意味着,所有任务需要排队,前⼀个任务结束,才会执⾏后⼀个任务。如果前⼀个任
务耗时很⻓,后⼀个任务就不得不⼀直等着。
这样所导致的问题是: 如果 JS 执⾏的时间过⻓,这样就会造成⻚⾯的渲染不连贯,导致⻚
⾯渲染加载阻塞的感觉。

11.2 同步任务和异步任务

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

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

同步

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

异步

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

image-20210802155012490

JS中所有任务可以分成两种,⼀种是同步任务(synchronous),另⼀种是异步任务
(asynchronous)。
同步任务指的是:
在主线程上排队执⾏的任务,只有前⼀个任务执⾏完毕,才能执⾏后⼀个任务;
异步任务指的是:
不进⼊主线程、⽽进⼊”任务队列”的任务,当主线程中的任务运⾏完了,才会从”任务队
列”取出异步任务放⼊主线程执⾏。

image-20210802155038495

11.3 JS执⾏机制(事件循环)

image-20210802155051295

image-20210802155058809

11.4 代码思考题

console.log(1);
document.onclick = function() {
console.log('click');
}
setTimeout(function() {
console.log(3)
}, 3000)
console.log(2);

12 - 元素偏移量 OFFSET 系列

12.1 offset 概述

offset 翻译过来就是偏移量, 我们使⽤ offset系列相关属性可以动态的得到该元素的位置(偏移)、⼤⼩等。

  1. 获得元素距离带有定位⽗元素的位置

  2. 获得元素⾃身的⼤⼩(宽度⾼度)

  3. 注意:返回的数值都不带单位

image-20210802155139338

12.2 offset 与 style 区别

offset

  • offset 可以得到任意样式表中的样式值
  • offset 系列获得的数值是没有单位的
  • offsetWidth 包含padding+border+width
  • offsetWidth 等属性是只读属性,只能获取不能赋值
  • 所以,我们想要获取元素⼤⼩位置,⽤offset更合适

style

  • style 只能得到⾏内样式表中的样式值
  • style.width 获得的是带有单位的字符串
  • style.width 获得不包含padding和border 的值
  • style.width 是可读写属性,可以获取也可以赋值
  • 所以,我们想要给元素更改值,则需要⽤style改变
  • 因为平时我们都是给元素注册触摸事件,所以重点记住 targetTocuhes

案例:获取⿏标在盒⼦内的坐标

  1. 我们在盒⼦内点击,想要得到⿏标距离盒⼦左右的距离。

  2. ⾸先得到⿏标在⻚⾯中的坐标(e.pageX, e.pageY)

  3. 其次得到盒⼦在⻚⾯中的距离 ( box.offsetLeft, box.offsetTop)

  4. ⽤⿏标距离⻚⾯的坐标减去盒⼦在⻚⾯中的距离,得到 ⿏标在盒⼦内的坐标

  5. 如果想要移动⼀下⿏标,就要获取最新的坐标,使⽤⿏标移动

var box = document.querySelector('.box');
box.addEventListener('mousemove', function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
this.innerHTML = 'x坐标是' + x + ' y坐标是' + y;
})

案例:模态框拖拽

弹出框,我们也称为模态框。

1.点击弹出层,会弹出模态框, 并且显示灰⾊半透明的遮挡层。

2.点击关闭按钮,可以关闭模态框,并且同时关闭灰⾊半透明遮挡层。

3.⿏标放到模态框最上⾯⼀⾏,可以按住⿏标拖拽模态框在⻚⾯中移动。

4.⿏标松开,可以停⽌拖动模态框移动

案例分析:

  1. 点击弹出层, 模态框和遮挡层就会显示出来 display:block;

  2. 点击关闭按钮,模态框和遮挡层就会隐藏起来 display:none;

  3. 在⻚⾯中拖拽的原理:⿏标按下并且移动, 之后松开⿏标

  4. 触发事件是⿏标按下mousedown,⿏标移动mousemove ⿏标松开 mouseup

  5. 拖拽过程: ⿏标移动过程中,获得最新的值赋值给模态框的left和top值,这样模态框可以跟着⿏标⾛了

  6. ⿏标按下触发的事件源是最上⾯⼀⾏,就是 id 为 title

  7. ⿏标的坐标减去 ⿏标在盒⼦内的坐标, 才是模态框真正的位置。

  8. ⿏标按下,我们要得到⿏标在盒⼦的坐标。

  9. ⿏标移动,就让模态框的坐标 设置为 :⿏标坐标 减去盒⼦坐标即可,注意移动事件写到按下事件⾥⾯。

  10. ⿏标松开,就停⽌拖拽,就是可以让⿏标移动事件解除

// 1. 获取元素
var login = document.querySelector('.login');
var mask = document.querySelector('.login-bg');
var link = document.querySelector('#link');
var closeBtn = document.querySelector('#closeBtn');
var title = document.querySelector('#title');
// 2. 点击弹出层这个链接 link 让mask 和login 显示出来
link.addEventListener('click', function() {
mask.style.display = 'block';
login.style.display = 'block';
})
// 3. 点击 closeBtn 就隐藏 mask 和 login
closeBtn.addEventListener('click', function() {
mask.style.display = 'none';
login.style.display = 'none';
})
// 4. 开始拖拽
// (1) 当我们⿏标按下, 就获得⿏标在盒⼦内的坐标
title.addEventListener('mousedown', function(e) {
var x = e.pageX - login.offsetLeft;
var y = e.pageY - login.offsetTop;
// (2) ⿏标移动的时候,把⿏标在⻚⾯中的坐标,减去 ⿏标在盒⼦内的坐标就
是模态框的left和top值
document.addEventListener('mousemove', move)
function move(e) {
login.style.left = e.pageX - x + 'px';
login.style.top = e.pageY - y + 'px';
}
// (3) ⿏标弹起,就让⿏标移动事件移除
document.addEventListener('mouseup', function() {
document.removeEventListener('mousemove', move);
})
})

案例:仿京东放⼤镜

  1. 整个案例可以分为三个功能模块

  2. ⿏标经过⼩图⽚盒⼦, ⻩⾊的遮挡层 和 ⼤图⽚盒⼦显示,离开隐藏2个盒⼦功能

  3. ⻩⾊的遮挡层跟随⿏标功能。

  4. 移动⻩⾊遮挡层,⼤图⽚跟随移动功能。

案例分析:

  1. ⻩⾊的遮挡层跟随⿏标功能。

  2. 把⿏标坐标给遮挡层不合适。因为遮挡层坐标以⽗盒⼦为准。

  3. ⾸先是获得⿏标在盒⼦的坐标。

  4. 之后把数值给遮挡层做为left 和top值。

  5. 此时⽤到⿏标移动事件,但是还是在⼩图⽚盒⼦内移动。

  6. 发现,遮挡层位置不对,需要再减去盒⼦⾃身⾼度和宽度的⼀半。

  7. 遮挡层不能超出⼩图⽚盒⼦范围。

  8. 如果⼩于零,就把坐标设置为0

  9. 如果⼤于遮挡层最⼤的移动距离,就把坐标设置为最⼤的移动距离

  10. 遮挡层的最⼤移动距离:⼩图⽚盒⼦宽度 减去 遮挡层盒⼦宽度

window.addEventListener('load', function() {
var preview_img = document.querySelector('.preview_img');
var mask = document.querySelector('.mask');
var big = document.querySelector('.big');
// 1. 当我们⿏标经过 preview_img 就显示和隐藏 mask 遮挡层 和 big ⼤盒⼦
preview_img.addEventListener('mouseover', function() {
mask.style.display = 'block';
big.style.display = 'block';
})
preview_img.addEventListener('mouseout', function() {
mask.style.display = 'none';
big.style.display = 'none';
})
// 2. ⿏标移动的时候,让⻩⾊的盒⼦跟着⿏标来⾛
preview_img.addEventListener('mousemove', function(e) {
// (1). 先计算出⿏标在盒⼦内的坐标
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
// console.log(x, y);
// (2) 减去盒⼦⾼度 300的⼀半 是 150 就是我们mask 的最终 left 和top值了
// (3) 我们mask 移动的距离
var maskX = x - mask.offsetWidth / 2;
var maskY = y - mask.offsetHeight / 2;
// (4) 如果x 坐标⼩于了0 就让他停在0 的位置
// 遮挡层的最⼤移动距离
var maskMax = preview_img.offsetWidth - mask.offsetWidth;
if (maskX <= 0) {
maskX = 0;
} else if (maskX >= maskMax) {
maskX = maskMax;
}
if (maskY <= 0) {
maskY = 0;
} else if (maskY >= maskMax) {
maskY = maskMax;
}
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
// 3. ⼤图⽚的移动距离 = 遮挡层移动距离 * ⼤图⽚最⼤移动距离 / 遮挡层的最⼤
移动距离
// ⼤图
var bigIMg = document.querySelector('.bigImg');
// ⼤图⽚最⼤移动距离
var bigMax = bigIMg.offsetWidth - big.offsetWidth;
// ⼤图⽚的移动距离 X Y
var bigX = maskX * bigMax / maskMax;
var bigY = maskY * bigMax / maskMax;
bigIMg.style.left = -bigX + 'px';
bigIMg.style.top = -bigY + 'px';
})
})

13 - 元素可视区 CLIENT 系列

13.1 client概述

client 翻译过来就是客户端,我们使⽤ client 系列的相关属性来获取元素可视区的相关信息。通过client 系列的相关属性可以动态的得到该元素的边框⼤⼩、元素⼤⼩等。

image-20210802155502694

image-20210802155509760

13.2. 淘宝 flexible.js 源码分析

⽴即执⾏函数 (function(){})() 或者 (function(){}())

主要作⽤: 创建⼀个独⽴的作⽤域。 避免了命名冲突问题

下⾯三种情况都会刷新⻚⾯都会触发 load 事件。

1.a标签的超链接

2.F5或者刷新按钮(强制刷新)

3.前进后退按钮

但是 ⽕狐中,有个特点,有个“往返缓存”,这个缓存中不仅保存着⻚⾯数据,还保存了DOM和JavaScript的状态;实际上是将整个⻚⾯都保存在了内存⾥。

所以此时后退按钮不能刷新⻚⾯。

此时可以使⽤ pageshow事件来触发。,这个事件在⻚⾯显示时触发,⽆论⻚⾯是否来⾃缓存。在重新加载⻚⾯中,pageshow会在load事件触发后触发;根据事件对象中的persisted来判断是否是缓存中的⻚⾯触发的pageshow事件

注意这个事件给window添加。

14 - 元素滚动 SCROLL 系列

14.1. scroll 概述

scroll 翻译过来就是滚动的,我们使⽤ scroll 系列的相关属性可以动态的得到该元素的⼤⼩、滚动距离

等。

image-20210802155610834

14.2. ⻚⾯被卷去的头部

如果浏览器的⾼(或宽)度不⾜以显示整个⻚⾯时,会⾃动出现滚动条。当滚动条向下滚动时,⻚⾯上⾯被隐藏掉的⾼度,我们就称为⻚⾯被卷去的头部。滚动条在滚动时会触发 onscroll事件。

查看⻚⾯被卷出的部分⽤ window.pageYoffset 和 window.pageXoffset 来 查 看 , 和

scrollTop 、 scrollLeft 的区别是⼀个是针对⻚⾯ document 的⼀个是针对⻚⾯元素的。

案例:仿淘宝固定右侧侧边栏

  1. 原先侧边栏是绝对定位

  2. 当⻚⾯滚动到⼀定位置,侧边栏改为固定定位

  3. ⻚⾯继续滚动,会让 返回顶部显示出来

案例分析:

  1. 需要⽤到⻚⾯滚动事件 scroll 因为是⻚⾯滚动,所以事件源是document

  2. 滚动到某个位置,就是判断⻚⾯被卷去的上部值。

  3. ⻚ ⾯ 被 卷 去 的 头 部 : 可 以 通 过 window.pageYOffset 获 得 如果是被卷去的左侧window.pageXOffset

  4. 注 意 , 元 素 被 卷 去 的 头 部 是 element.scrollTop , 如果是⻚⾯被卷去的头部 则 是window.pageYOffset

  5. 其实这个值 可以通过盒⼦的 offsetTop可以得到,如果⼤于等于这个值,就可以让盒⼦固定定位了

//1. 获取元素
var sliderbar = document.querySelector('.slider-bar');
var banner = document.querySelector('.banner');
// banner.offestTop 就是被卷去头部的⼤⼩ ⼀定要写到滚动的外⾯
var bannerTop = banner.offsetTop
// 当我们侧边栏固定定位之后应该变化的数值
var sliderbarTop = sliderbar.offsetTop - bannerTop;
// 获取main 主体元素
var main = document.querySelector('.main');
var goBack = document.querySelector('.goBack');
var mainTop = main.offsetTop;
// 2. ⻚⾯滚动事件 scroll
document.addEventListener('scroll', function() {
// console.log(11);
// window.pageYOffset ⻚⾯被卷去的头部
// console.log(window.pageYOffset);
// 3 .当我们⻚⾯被卷去的头部⼤于等于了 172 此时 侧边栏就要改为固定定位
if (window.pageYOffset >= bannerTop) {
sliderbar.style.position = 'fixed';
sliderbar.style.top = sliderbarTop + 'px';
} else {
sliderbar.style.position = 'absolute';
sliderbar.style.top = '300px';
}
// 4. 当我们⻚⾯滚动到main盒⼦,就显示 goback模块
if (window.pageYOffset >= mainTop) {
goBack.style.display = 'block';
} else {
goBack.style.display = 'none';
}
})

14.3. ⻚⾯被卷去的头部兼容性解决⽅案

需要注意的是,⻚⾯被卷去的头部,有兼容性问题,因此被卷去的头部通常有如下⼏种写法:

  1. 声明了 DTD,使⽤ document.documentElement.scrollTop

  2. 未声明 DTD,使⽤ document.body.scrollTop

  3. 新⽅法 window.pageYOffset和 window.pageXOffset,IE9 开始⽀持

function getScroll() {
return {
left: window.pageXOffset || document.documentElement.scrollLeft ||
document.body.scrollLeft||0,
top: window.pageYOffset || document.documentElement.scrollTop ||
document.body.scrollTop || 0
};
}
使⽤的时候 getScroll().left

15 - 三⼤系列总结

image-20210802155738366

他们主要⽤法:

1.offset系列 经常⽤于获得元素位置 offsetLeft offsetTop

2.client经常⽤于获取元素⼤⼩ clientWidth clientHeight

3.scroll 经常⽤于获取滚动距离 scrollTop scrollLeft

4.注意⻚⾯滚动的距离通过 window.pageXOffset 获得

16 - 动画函数封装

动画实现原理

核⼼原理:通过定时器 setInterval() 不断移动盒⼦位置。

实现步骤:

  1. 获得盒⼦当前位置

  2. 让盒⼦在当前位置加上1个移动距离

  3. 利⽤定时器不断重复这个操作

  4. 加⼀个结束定时器的条件

  5. 注意此元素需要添加定位,才能使⽤element.style.left

动画函数给不同元素记录不同定时器

如果多个元素都使⽤这个动画函数,每次都要var 声明定时器。我们可以给不同的元素使⽤不同的定时器(⾃⼰专⻔⽤⾃⼰的定时器)。

核⼼原理:利⽤ JS 是⼀⻔动态语⾔,可以很⽅便的给当前对象添加属性。

function animate(obj, target) {
// 当我们不断的点击按钮,这个元素的速度会越来越快,因为开启了太多的定时
器
// 解决⽅案就是 让我们元素只有⼀个定时器执⾏
// 先清除以前的定时器,只保留当前的⼀个定时器执⾏
clearInterval(obj.timer);
obj.timer = setInterval(function() {
if (obj.offsetLeft >= target) {
// 停⽌动画 本质是停⽌定时器
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + 1 + 'px';
}, 30);
}

缓动效果原理

缓动动画就是让元素运动速度有所变化,最常⻅的是让速度慢慢停下来

思路:

  1. 让盒⼦每次移动的距离慢慢变⼩,速度就会慢慢落下来。

  2. 核⼼算法: (⽬标值 - 现在的位置) / 10 做为每次移动的距离步⻓

  3. 停⽌的条件是: 让当前盒⼦位置等于⽬标位置就停⽌定时器

  4. 注意步⻓值需要取整

动画函数多个⽬标值之间移动

可以让动画函数从 800 移动到 500。

当我们点击按钮时候,判断步⻓是正值还是负值

1.如果是正值,则步⻓往⼤了取整

2.如果是负值,则步⻓ 向⼩了取整

动函数添加回调函数

回调函数原理:函数可以作为⼀个参数。将这个函数作为参数传到另⼀个函数⾥⾯,当那个函数执⾏完之后,再执⾏传进去的这个函数,这个过程就叫做回调。

回调函数写的位置:定时器结束的位置。

动画完整版代码

function animate(obj, target, callback) {
// console.log(callback); callback = function() {} 调⽤的时候 callback()
// 先清除以前的定时器,只保留当前的⼀个定时器执⾏
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步⻓值写到定时器的⾥⾯
// 把我们步⻓值改为整数 不要出现⼩数的问题
// var step = Math.ceil((target - obj.offsetLeft) / 10);
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
// 停⽌动画 本质是停⽌定时器
clearInterval(obj.timer);
// 回调函数写到定时器结束⾥⾯
// if (callback) {
// // 调⽤函数
// callback();
// }
callback && callback();
}
// 把每次加1 这个步⻓值改为⼀个慢慢变⼩的值 步⻓公式:(⽬标值 - 现在的位
置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}

17 - 常⻅⽹⻚特效案例

17.1. ⽹⻚轮播图

轮播图也称为焦点图,是⽹⻚中⽐较常⻅的⽹⻚特效。功能需求:

1.⿏标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。

2.点击右侧按钮⼀次,图⽚往左播放⼀张,以此类推,左侧按钮同理。

3.图⽚播放的同时,下⾯⼩圆圈模块跟随⼀起变化。

4.点击⼩圆圈,可以播放相应图⽚。

5.⿏标不经过轮播图,轮播图也会⾃动播放图⽚。

6.⿏标经过,轮播图模块, ⾃动播放停⽌。

window.addEventListener('load', function() {
// 1. 获取元素
var arrow_l = document.querySelector('.arrow-l');
var arrow_r = document.querySelector('.arrow-r');
var focus = document.querySelector('.focus');
var focusWidth = focus.offsetWidth;
// 2. ⿏标经过focus 就显示隐藏左右按钮
focus.addEventListener('mouseenter', function() {
arrow_l.style.display = 'block';
arrow_r.style.display = 'block';
clearInterval(timer);
timer = null; // 清除定时器变量
});
focus.addEventListener('mouseleave', function() {
arrow_l.style.display = 'none';
arrow_r.style.display = 'none';
timer = setInterval(function() {
//⼿动调⽤点击事件
arrow_r.click();
}, 2000);
});
// 3. 动态⽣成⼩圆圈 有⼏张图⽚,我就⽣成⼏个⼩圆圈
var ul = focus.querySelector('ul');
var ol = focus.querySelector('.circle');
// console.log(ul.children.length);
for (var i = 0; i < ul.children.length; i++) {
// 创建⼀个⼩li
var li = document.createElement('li');
// 记录当前⼩圆圈的索引号 通过⾃定义属性来做
li.setAttribute('index', i);
// 把⼩li插⼊到ol ⾥⾯
ol.appendChild(li);
// 4. ⼩圆圈的排他思想 我们可以直接在⽣成⼩圆圈的同时直接绑定点击事件
li.addEventListener('click', function() {
// ⼲掉所有⼈ 把所有的⼩li 清除 current 类名
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = '';
}
// 留下我⾃⼰ 当前的⼩li 设置current 类名
this.className = 'current';
// 5. 点击⼩圆圈,移动图⽚ 当然移动的是 ul
// ul 的移动距离 ⼩圆圈的索引号 乘以 图⽚的宽度 注意是负值
// 当我们点击了某个⼩li 就拿到当前⼩li 的索引号
var index = this.getAttribute('index');
// 当我们点击了某个⼩li 就要把这个li 的索引号给 num
num = index;
// 当我们点击了某个⼩li 就要把这个li 的索引号给 circle
circle = index;
// num = circle = index;
console.log(focusWidth);
console.log(index);
animate(ul, -index * focusWidth);
})
}
// 把ol⾥⾯的第⼀个⼩li设置类名为 current
ol.children[0].className = 'current';
// 6. 克隆第⼀张图⽚(li)放到ul 最后⾯
var first = ul.children[0].cloneNode(true);
ul.appendChild(first);
// 7. 点击右侧按钮, 图⽚滚动⼀张
var num = 0;
// circle 控制⼩圆圈的播放
var circle = 0;
// flag 节流阀
var flag = true;
arrow_r.addEventListener('click', function() {
if (flag) {
flag = false; // 关闭节流阀
// 如果⾛到了最后复制的⼀张图⽚,此时 我们的ul 要快速复原 left 改为 0
if (num == ul.children.length - 1) {
ul.style.left = 0;
num = 0;
}
num++;
animate(ul, -num * focusWidth, function() {
flag = true; // 打开节流阀
});
// 8. 点击右侧按钮,⼩圆圈跟随⼀起变化 可以再声明⼀个变量控制⼩圆圈的播
放
circle++;
// 如果circle == 4 说明⾛到最后我们克隆的这张图⽚了 我们就复原
if (circle == ol.children.length) {
circle = 0;
}
// 调⽤函数
circleChange();
}
});
// 9. 左侧按钮做法
arrow_l.addEventListener('click', function() {
if (flag) {
flag = false;
if (num == 0) {
num = ul.children.length - 1;
ul.style.left = -num * focusWidth + 'px';
}
num--;
animate(ul, -num * focusWidth, function() {
flag = true;
});
// 点击左侧按钮,⼩圆圈跟随⼀起变化 可以再声明⼀个变量控制⼩圆圈的播放
circle--;
// 如果circle < 0 说明第⼀张图⽚,则⼩圆圈要改为第4个⼩圆圈(3)
// if (circle < 0) {
// circle = ol.children.length - 1;
// }
circle = circle < 0 ? ol.children.length - 1 : circle;
// 调⽤函数
circleChange();
}
});
function circleChange() {
// 先清除其余⼩圆圈的current类名
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = '';
}
// 留下当前的⼩圆圈的current类名
ol.children[circle].className = 'current';
}
// 10. ⾃动播放轮播图
var timer = setInterval(function() {
//⼿动调⽤点击事件
arrow_r.click();
}, 2000);
})

17.2. 节流阀

防⽌轮播图按钮连续点击造成播放过快。

节流阀⽬的:当上⼀个函数动画内容执⾏完毕,再去执⾏下⼀个函数动画,让事件⽆法连续触发。

核⼼实现思路:利⽤回调函数,添加⼀个变量来控制,锁住函数和解锁函数。

开始设置⼀个变量var flag= true;If(flag){flag = false; do something} 关闭⽔⻰头

利⽤回调函数动画执⾏完毕, flag = true 打开⽔⻰头

17.3. 返回顶部

  1. 带有动画的返回顶部

  2. 此时可以继续使⽤我们封装的动画函数

  3. 只需要把所有的left 相关的值改为 跟 ⻚⾯垂直滚动距离相关就可以了

  4. ⻚⾯滚动了多少,可以通过 window.pageYOffset 得到

  5. 最后是⻚⾯滚动,使⽤ window.scroll(x,y)

//1. 获取元素
var sliderbar = document.querySelector('.slider-bar');
var banner = document.querySelector('.banner');
// banner.offestTop 就是被卷去头部的⼤⼩ ⼀定要写到滚动的外⾯
var bannerTop = banner.offsetTop
// 当我们侧边栏固定定位之后应该变化的数值
var sliderbarTop = sliderbar.offsetTop - bannerTop;
// 获取main 主体元素
var main = document.querySelector('.main');
var goBack = document.querySelector('.goBack');
var mainTop = main.offsetTop;
// 2. ⻚⾯滚动事件 scroll
document.addEventListener('scroll', function() {
// console.log(11);
// window.pageYOffset ⻚⾯被卷去的头部
// console.log(window.pageYOffset);
// 3 .当我们⻚⾯被卷去的头部⼤于等于了 172 此时 侧边栏就要改为固定
定位
if (window.pageYOffset >= bannerTop) {
sliderbar.style.position = 'fixed';
sliderbar.style.top = sliderbarTop + 'px';
} else {
sliderbar.style.position = 'absolute';
sliderbar.style.top = '300px';
}
// 4. 当我们⻚⾯滚动到main盒⼦,就显示 goback模块
if (window.pageYOffset >= mainTop) {
goBack.style.display = 'block';
} else {
goBack.style.display = 'none';
}
})
// 3. 当我们点击了返回顶部模块,就让窗⼝滚动的⻚⾯的最上⽅
goBack.addEventListener('click', function() {
// ⾥⾯的x和y 不跟单位的 直接写数字即可
// window.scroll(0, 0);
// 因为是窗⼝滚动 所以对象是window
animate(window, 0);
});

案例:筋头云案例

  1. 利⽤动画函数做动画效果

  2. 原先筋⽃云的起始位置是0

  3. ⿏标经过某个⼩li,把当前⼩li的offsetLeft 位置做为⽬标值即可

  4. ⿏标离开某个⼩li,就把⽬标值设为 0

  5. 如果点击了某个⼩li, 就把li当前的位置存储起来,做为筋⽃云的起始位置

window.addEventListener('load', function() {
// 1. 获取元素
var cloud = document.querySelector('.cloud');
var c_nav = document.querySelector('.c-nav');
var lis = c_nav.querySelectorAll('li');
// 2. 给所有的⼩li绑定事件
// 这个current 做为筋⽃云的起始位置
var current = 0;
for (var i = 0; i < lis.length; i++) {
// (1) ⿏标经过把当前⼩li 的位置做为⽬标值
lis[i].addEventListener('mouseenter', function() {
animate(cloud, this.offsetLeft);
});
// (2) ⿏标离开就回到起始的位置
lis[i].addEventListener('mouseleave', function() {
animate(cloud, current);
});
// (3) 当我们⿏标点击,就把当前位置做为⽬标值
lis[i].addEventListener('click', function() {
current = this.offsetLeft;
});
}
})

18 - 触屏事件

18.1. 触屏事件概述

移动端浏览器兼容性较好,我们不需要考虑以前 JS 的兼容性问题,可以放⼼的使⽤原⽣ JS 书写效果,但是移动端也有⾃⼰独特的地⽅。⽐如触屏事件 touch(也称触摸事件),Android和 IOS 都有。

touch 对象代表⼀个触摸点。触摸点可能是⼀根⼿指,也可能是⼀根触摸笔。触屏事件可响应⽤户⼿指(或触控笔)对屏幕或者触控板操作。

常⻅的触屏事件如下:

image-20210802160157014

18.2. 触摸事件对象(TouchEvent)

TouchEvent 是⼀类描述⼿指在触摸平⾯(触摸屏、触摸板等)的状态变化的事件。这类事件⽤于描述⼀个或多个触点,使开发者可以检测触点的移动,触点的增加和减少,等等

touchstart、touchmove、touchend 三个事件都会各⾃有事件对象。

触摸事件对象重点我们看三个常⻅对象列表:

image-20210802160226913

因为平时我们都是给元素注册触摸事件,所以重点记住 targetTocuhes

案例:移动端拖动元素

  1. touchstart、touchmove、touchend可以实现拖动元素

  2. 但是拖动元素需要当前⼿指的坐标值 我们可以使⽤ targetTouches[0] ⾥⾯的pageX 和pageY

  3. 移动端拖动的原理: ⼿指移动中,计算出⼿指移动的距离。然后⽤盒⼦原来的位置 + ⼿指移动的距离

  4. ⼿指移动的距离: ⼿指滑动中的位置 减去 ⼿指刚开始触摸的位置

拖动元素三步曲:

(1) 触摸元素 touchstart: 获取⼿指初始坐标,同时获得盒⼦原来的位置

(2) 移动⼿指 touchmove: 计算⼿指的滑动距离,并且移动盒⼦

(3) 离开⼿指 touchend:

注意: ⼿指移动也会触发滚动屏幕所以这⾥要阻⽌默认的屏幕滚动 e.preventDefault();

19 - 移动端常⻅特效

19.1 移动轮播图

移动端轮播图功能和基本PC端⼀致。

  1. 可以⾃动播放图⽚

  2. ⼿指可以拖动播放轮播图

案例分析:

  1. ⾃动播放功能

  2. 开启定时器

  3. 移动端移动,可以使⽤translate 移动

  4. 想要图⽚优雅的移动,请添加过渡效果

  5. image-20210802160331853

  6. ⾃动播放功能-⽆缝滚动

  7. 注意,我们判断条件是要等到图⽚滚动完毕再去判断,就是过渡完成后判断

  8. 此时需要添加检测过渡完成事件 transitionend

  9. 判断条件:如果索引号等于 3 说明⾛到最后⼀张图⽚,此时 索引号要复原为 0

  10. 此时图⽚,去掉过渡效果,然后移动

  11. 如果索引号⼩于0, 说明是倒着⾛, 索引号等于2

  12. 此时图⽚,去掉过渡效果,然后移动

image-20210802160354701

20 - CLASSLIST 属性

classList属性是HTML5新增的⼀个属性,返回元素的类名。但是ie10以上版本⽀持。

该属性⽤于在元素中添加,移除及切换 CSS 类。有以下⽅法

添加类:

element.classList.add(’类名’);

focus.classList.add('current');

移除类:

element.classList.remove(’类名’);

focus.classList.remove('current');

切换类:

element.classList.toggle(’类名’);

focus.classList.toggle('current');

注意:以上⽅法⾥⾯,所有类名都不带点

案例分析

  1. ⼩圆点跟随变化效果

  2. 把ol⾥⾯li带有current类名的选出来去掉类名 remove

  3. 让当前索引号的⼩li 加上 current add

  4. 但是,是等着过渡结束之后变化,所以这个写到 transitionend 事件⾥⾯

image-20210802160455518

  1. ⼿指滑动轮播图

  2. 本质就是ul跟随⼿指移动,简单说就是移动端拖动元素

  3. 触摸元素touchstart: 获取⼿指初始坐标

  4. 移动⼿指touchmove: 计算⼿指的滑动距离,并且移动盒⼦

  5. 离开⼿指touchend: 根据滑动的距离分不同的情况

  6. 如果移动距离⼩于某个像素 就回弹原来位置

  7. 如果移动距离⼤于某个像素就上⼀张下⼀张滑动。

  8. 滑动也分为左滑动和右滑动判断的标准是 移动距离正负 如果是负值就是左滑 反之右滑

  9. 如果是左滑就播放下⼀张 (index++)

  10. 如果是右滑就播放上⼀张 (index--)

image-20210802160521550

image-20210802160529486

案例:返回顶部

当⻚⾯滚动某个地⽅,就显示,否则隐藏

点击可以返回顶部

案例分析

  1. 滚动某个地⽅显示

  2. 事件:scroll⻚⾯滚动事件

  3. 如果被卷去的头部(window.pageYOffset )⼤于某个数值

  4. 点击,window.scroll(0,0) 返回顶部

image-20210802160554829

21 - CLICK 延时解决⽅案

移动端 click 事件会有 300ms 的延时,原因是移动端屏幕双击会缩放(double tap to zoom) ⻚⾯。

解决⽅案:

  1. 禁⽤缩放。 浏览器禁⽤默认的双击缩放⾏为并且去掉300ms 的点击延迟。
<meta name="viewport" content="user-scalable=no">

2.利⽤touch事件⾃⼰封装这个事件解决300ms 延迟。

原理就是:

  1. 当我们⼿指触摸屏幕,记录当前触摸时间

  2. 当我们⼿指离开屏幕, ⽤离开的时间减去触摸的时间

  3. 如果时间⼩于150ms,并且没有滑动过屏幕, 那么我们就定义为点击

  4. 代码如下:

//封装tap,解决click 300ms 延时
function tap (obj, callback) {
var isMove = false;
var startTime = 0; // 记录触摸时候的时间变量
obj.addEventListener('touchstart', function (e) {
startTime = Date.now(); // 记录触摸时间
});
obj.addEventListener('touchmove', function (e) {
isMove = true; // 看看是否有滑动,有滑动算拖拽,不算点击
});
obj.addEventListener('touchend', function (e) {
if (!isMove && (Date.now() - startTime) < 150) { // 如果⼿指触摸
和离开时间⼩于150ms 算点击
callback && callback(); // 执⾏回调函数
}
isMove = false; // 取反 重置
startTime = 0;
});
}
//调⽤
tap(div, function(){ // 执⾏代码 });
  1. 使⽤插件。fastclick 插件解决300ms 延迟。

image-20210802160651737

22 - 移动端常⽤开发插件

22.1. 什么是插件

移动端要求的是快速开发,所以我们经常会借助于⼀些插件来帮我完成操作,那么什么是插件呢?

JS 插件是 js ⽂件,它遵循⼀定规范编写,⽅便程序展示效果,拥有特定功能且⽅便调⽤。如轮播图和瀑

布流插件。

特点:它⼀般是为了解决某个问题⽽专⻔存在,其功能单⼀,并且⽐较⼩。

我们以前写的animate.js 也算⼀个最简单的插件

fastclick 插件解决 300ms 延迟。 使⽤延时

GitHub官⽹地址: https://github.com/ftlabs/fastclick

22.2. 插件的使⽤

  1. 引⼊ js 插件⽂件。

  2. 按照规定语法使⽤。

  3. fastclick 插件解决 300ms 延迟。 使⽤延时

  4. GitHub官⽹地址: https://github.com/ftlabs/fastclick

if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body);
}, false);
}

22.3. Swiper 插件的使⽤

中⽂官⽹地址: https://www.swiper.com.cn/

1. 引⼊插件相关⽂件。

2. 按照规定语法使⽤

22.4. 其他移动端常⻅插件

lsuperslide: http://www.superslide2.com/

l iscroll: https://github.com/cubiq/iscroll

22.5. 插件的使⽤总结

1.确认插件实现的功能

2.去官⽹查看使⽤说明

3.下载插件

4.打开demo实例⽂件,查看需要引⼊的相关⽂件,并且引⼊

5.复制demo实例⽂件中的结构html,样式css以及js代码

22.6. 移动端视频插件 zy.media.js

H5 给我们提供了 video 标签,但是浏览器的⽀持情况不同。

不同的视频格式⽂件,我们可以通过source解决。

但是外观样式,还有暂停,播放,全屏等功能我们只能⾃⼰写代码解决。

这个时候我们可以使⽤插件⽅式来制作。

我们可以通过 JS 修改元素的⼤⼩、颜⾊、位置等样式。

23 - 移动端常⽤开发框架

23.1. 移动端视频插件 zy.media.js

框架,顾名思义就是⼀套架构,它会基于⾃身的特点向⽤户提供⼀套较为完整的解决⽅案。框架的控制

权在框架本身,使⽤者要按照框架所规定的某种规范进⾏开发。插件⼀般是为了解决某个问题⽽专⻔存在,其功能单⼀,并且⽐较⼩。

前端常⽤的框架有 Bootstrap、Vue、Angular、React 等。既能开发PC端,也能开发移动端

前端常⽤的移动端插件有 swiper、superslide、iscroll等。

框架: ⼤⽽全,⼀整套解决⽅案

插件: ⼩⽽专⼀,某个功能的解决⽅案

23.2. Bootstrap

Bootstrap 是⼀个简洁、直观、强悍的前端开发框架,它让 web 开发更迅速、简单。

它能开发PC端,也能开发移动端

Bootstrap JS插件使⽤步骤:

1.引⼊相关js ⽂件

2.复制HTML 结构

3.修改对应样式

4.修改相应JS 参数

24 - 本地存储

随着互联⽹的快速发展,基于⽹⻚的应⽤越来越普遍,同时也变的越来越复杂,为了满⾜各种各样的需

求,会经常性在本地存储⼤量的数据,HTML5规范提出了相关解决⽅案。

24.1.本地存储特性

1、数据存储在⽤户浏览器中

2、设置、读取⽅便、甚⾄⻚⾯刷新不丢失数据

3、容量较⼤,sessionStorage约5M、localStorage约20M

4、只能存储字符串,可以将对象JSON.stringify() 编码后存储

24.2.window.sessionStorage

1、⽣命周期为关闭浏览器窗⼝

2、在同⼀个窗⼝(⻚⾯)下数据可以共享

3、以键值对的形式存储使⽤

存储数据:

sessionStorage.setItem(key, value)

获取数据:

sessionStorage.getItem(key)

删除数据:

sessionStorage.removeItem(key)

清空数据:(所有都清除掉)

sessionStorage.clear()

24.3.window.localStorage

1、声明周期永久⽣效,除⾮⼿动删除 否则关闭⻚⾯也会存在

2、可以多窗⼝(⻚⾯)共享(同⼀浏览器可以共享)

3,以键值对的形式存储使⽤

存储数据:

localStorage.setItem(key, value)

获取数据:

localStorage.getItem(key)

删除数据:

localStorage.removeItem(key)

清空数据:(所有都清除掉)

localStorage.clear()

案例:记住⽤户名

如果勾选记住⽤户名, 下次⽤户打开浏览器,就在⽂本框⾥⾯⾃动显示上次登录的⽤户名

案例分析

  1. 把数据存起来,⽤到本地存储

  2. 关闭⻚⾯,也可以显示⽤户名,所以⽤到localStorage

  3. 打开⻚⾯,先判断是否有这个⽤户名,如果有,就在表单⾥⾯显示⽤户名,并且勾选复选框

  4. 当复选框发⽣改变的时候change事件

  5. 如果勾选,就存储,否则就移除

image-20210802160953330

原文地址:https://www.cnblogs.com/zgboy/p/15090387.html