1 JS简介
更多JS内容可以看MDN:点击传送 浏览器分成两部分:渲染引擎和 JS 引擎
- 渲染引擎:用来解析HTML与CSS,俗称内核,比如 chrome 浏览器的 blink ,老版本的 webkit
- JS 引擎:也称为 JS 解释器。 用来读取网页中的JavaScript代码,对其处理后运行,比如 chrome 浏览器的 V8
浏览器本身并不会执行JS代码,而是通过内置 JavaScript 引擎(解释器) 来执行 JS 代码 。JS 引擎执行代码时逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以 JavaScript 语言归为脚本语言,会逐行解释执行。
1.1 ECMAScript
ECMAScript 是由ECMA 国际( 原欧洲计算机制造商协会)进行标准化的一门编程语言,这种语言在万维网上应用广泛,它往往被称为 JavaScript 或 JScript,但实际上后两者是 ECMAScript 语言的实现和扩展。
ECMAScript:ECMAScript 规定了JS的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套JS语法工业标准。
1.2 DOM-文档对象模型
文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标记语言的标准编程接口。通过 DOM 提供的接口可以对页面上的各种元素进行操作(大小、位置、颜色等)。
1.3 BOM-浏览器对象模型
BOM (Browser Object Model,简称BOM) 是指浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等。
2 变量
变量在内存中的存储
本质:变量是程序在内存中申请的一块用来存放数据的空间。
声明变量并赋值我们称之为变量的初始化
2.1 命名规范
- 由字母(A-Za-z)、数字(0-9)、下划线(_)、美元符号( $ )组成,如:usrAge, num01, _name
- 严格区分大小写。var app; 和 var App; 是两个变量
- 不能 以数字开头。 18age 是错误的
- 不能 是关键字、保留字。例如:var、for、while
- 变量名必须有意义。 MMD BBD nl → age
- 遵守驼峰命名法。首字母小写,后面单词的首字母需要大写。 myFirstName
3 数据类型
3.1简单数据类型
简单数据类型存放到栈里面
3.1.1 数字型 Number
3.1.1.1 数字型范围
alert(Number.MAX_VALUE); // 1.7976931348623157e+308
alert(Number.MIN_VALUE); // 5e-324
最大值:Number.MAX_VALUE,这个值为: 1.7976931348623157e+308
最小值:Number.MIN_VALUE,这个值为:5e-32
3.1.1.2 数字型三个特殊值
alert(Infinity); // Infinity
alert(-Infinity); // -Infinity
alert(NaN); // NaN
Infinity:代表无穷大,大于任何数值
-Infinity:代表无穷小,小于任何数值
NaN :Not a number,代表一个非数值
3.1.1.3 isNaN()
用来判断一个变量是否为非数字的类型,返回 true 或者 false
3.1.2 字符串型 String
HTML 标签里面的属性使用的是双引号,JS 更推荐使用单引号。
根据位置返回字符:
根据字符返回位置:
字符串操作方法:
其他方法:
- toUpperCase() //转换大写
- toLowerCase() //转换小写
- replace() //用于在字符串中用一些字符替换另一些字符
- split() //用于切分字符串,它可以将字符串切分为数组。在切分完毕之后,返回的是一个新数组。
3.1.3 布尔型 Boolean
布尔型和数字型相加的时候, true 的值为 1 ,false 的值为 0
3.1.4 Undefined 和 Null
//undefined
var variable;
console.log(variable); // undefined
console.log('你好' + variable); // 你好undefined
console.log(11 + variable); // NaN
console.log(true + variable); // NaN
//null
var vari = null;
console.log('你好' + vari); // 你好null
console.log(11 + vari); // 11
console.log(true + vari); // 1
3.1.5 获取检测变量的数据类型
typeof 可用来获取检测变量的数据类型
3.1.6 数据类型转换
3.1.6.1 转换为字符串
3.1.6.2 转换为数字型
隐式转换是我们在进行算数运算的时候,JS 自动转换了数据类型
3.1.6.3 转换为布尔型
代表空、否定的值会被转换为 false ,如 ‘’、0、NaN、null、undefined
其余值都会被转换为 true
3.2 复杂类型(引用类型)
复杂数据类型,在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型
通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等
复杂数据类型存放到堆里面
4 关键字和保留字
4.1 关键字
关键字:是指 JS本身已经使用了的字,不能再用它们充当变量名、方法名。
包括:break、case、catch、continue、default、delete、do、else、finally、for、function、if、in、instanceof、new、return、switch、this、throw、try、typeof、var、void、while、with 等。
4.2 保留字
保留字:实际上就是预留的“关键字”,意思是现在虽然还不是关键字,但是未来可能会成为关键字,同样不能使用它们当变量名或方法名。
包括:boolean、byte、char、class、const、debugger、double、enum、export、extends、fimal、float、goto、implements、import、int、interface、long、mative、package、private、protected、public、short、static、super、synchronized、throws、transient、volatile 等。
注意:如果将保留字用作变量名或函数名,那么除非将来的浏览器实现了该保留字,否则很可能收不到任何错误消息。当浏览器将其实现后,该单词将被看做关键字,如此将出现关键字错误。
5 运算符
JavaScript中常用的运算符有:
- 算数运算符
- 递增和递减运算符
- 比较运算符
- 逻辑运算符
- 赋值运算符
5.1 算数运算符
+ - * / %
浮点数的精度问题
var result = 0.1 + 0.2; // 结果不是 0.3,而是:0.30000000000000004
console.log(0.07 * 100); // 结果不是 7, 而是:7.000000000000001
注:不要直接判断两个浮点数是否相等
5.2 递增和递减运算符
如果需要反复给数字变量添加或减去1,可以使用递增(++)和递减( – )运算符来完成。
++num 前置递增:先自加,后返回值
num++:先返回原值,后自加
5.3 比较运算符
<
>
>=
<=
==
!=
===
!==
5.4 逻辑运算符
逻辑与&& 逻辑或|| 取反符!
5.5 赋值运算符
=
+=
-=
*=
/=
%=
5.6 运算符优先级
- 一元运算符里面的逻辑非优先级很高
- 逻辑与比逻辑或优先级高
6 流程控制
流程控制主要有三种结构,分别是顺序结构、分支结构和循环结构,这三种结构代表三种代码执行的顺序。
6.1 顺序流程控制
程序会按照代码的先后顺序,依次执行
6.2 分支流程控制
JS 语言提供了两种分支结构语句
- if 语句
- switch 语句
6.2.1 if
if (条件表达式1) {
语句1;
} else if (条件表达式2) {
语句2;
} else if (条件表达式3) {
语句3;
....
} else {
// 上述条件都不成立执行此处代码
}
6.2.2 switch
switch( 表达式 ){
case value1:
// 表达式 等于 value1 时要执行的代码
break;
case value2:
// 表达式 等于 value2 时要执行的代码
break;
default:
// 表达式 不等于任何一个 value 时要执行的代码
}
关键字 switch 后面括号内可以是表达式或值, 通常是一个变量
注: 执行case 里面的语句时,如果没有break,则继续执行下一个case里面的语句。
6.2.3 三元表达式
表达式1 ? 表达式2 : 表达式3;
如果表达式1为 true ,则返回表达式2的值,如果表达式1为 false,则返回表达式3的值
6.3 循环
在Js 中,主要有三种类型的循环语句:
- for 循环
- while 循环
- do…while 循环
6.3.1 for 循环
for(初始化变量; 条件表达式; 操作表达式){
//循环体语句
}
6.3.2 while循环
while (条件表达式) {
// 循环体代码
}
使用 while 循环时一定要注意,它必须要有退出条件,否则会成为死循环
6.3.3 do while 循环
do {
// 循环体代码 - 条件表达式为 true 时重复执行循环体代码
} while(条件表达式);
先再执行循环体,再判断,我们会发现 do…while 循环语句至少会执行一次循环体代码
6.3.4 continue break
continue: 用于立即跳出本次循环,继续下一次循环。
break: 用于立即跳出整个循环(循环结束)。
7 数组
JS 中创建数组有两种方式:
- 利用 new 创建数组
- 利用数组字面量创建数组
var 数组名 = new Array();
var 数组名 = [];
7.1 检测是否为数组
instanceof 运算符,可以判断一个对象是否属于某种类型
Array.isArray()用于判断一个对象是否为数组,isArray() 是 HTML5 中提供的方法
var arr = [1, 23];
var obj = {};
console.log(arr instanceof Array); // true
console.log(obj instanceof Array); // false
console.log(Array.isArray(arr)); // true
console.log(Array.isArray(obj)); // false
7.2 添加删除数组元素的方法
7.3 数组排序
7.4 数组索引方法
7.5 数组转换为字符串
7.6 其他方法
8 函数
概念:封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。
// 声明函数
function 函数名() {
//函数体代码
}
// 调用函数
函数名();
注:声明函数本身并不会执行代码,只有调用函数时才会执行函数体代码。
break :结束当前的循环体(如 for、while)
continue :跳出本次循环,继续执行下次循环(如 for、while)
return :不仅可以退出循环,还能够返回 return 语句中的值,同时还可以结束当前的函数体内的代码
8.1 arguments的使用
当我们不确定有多少个参数传递的时候,可以用 arguments 来获取。在 JavaScript 中,arguments 实际上它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象,arguments 对象中存储了传递的所有实参。
arguments展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点:
- 具有 length 属性
- 按索引方式储存数据
- 不具有数组的 push , pop 等方法
9 对象
在 JavaScript 中,现阶段我们可以采用三种方式创建对象(object):
- 利用字面量创建对象
- 利用 new Object 创建对象
- 利用构造函数创建对象
9.1 利用字面量创建对象
//创建
var star = {
name : 'zhangsan',
age : 18,
sex : '男',
sayHi : function(){
alert('大家好啊~');
}
};
//调用
console.log(star.name) // 调用名字属性
console.log(star['name']) // 调用名字属性
star.sayHi(); // 调用 sayHi 方法,注意,一定不要忘记带后面的括号
9.2 利用new Object创建对象
var andy = new Obect();
andy.name = 'zhangsan';
andy.age = 18;
andy.sex = '男';
andy.sayHi = function(){
alert('大家好啊~');
}
9.3 利用构造函数创建对象
构造函数 :是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
在 js 中,使用构造函数要时要注意以下两点:
- 构造函数用于创建某一类对象,其首字母要大写
- 构造函数要和 new 一起使用才有意义
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.sayHi = function() {
alert('我的名字叫:' + this.name + ',年龄:' + this.age + ',性别:' + this.sex);
}
}
var bigbai = new Person('大白', 100, '男');
var smallbai = new Person('小白', 21, '男');
console.log(bigbai.name);
console.log(smallbai.name);
注意:
- 构造函数约定首字母大写。
- 函数内的属性和方法前面需要添加 this ,表示当前对象的属性和方法。
- 构造函数中不需要 return 返回结果。
- 当我们创建对象的时候,必须用 new 来调用构造函数。
9.4 遍历对象属性
for…in 语句用于对数组或者对象的属性进行循环操作。
for (var k in obj) {
console.log(k); // 这里的 k 是属性名
console.log(obj[k]); // 这里的 obj[k] 是属性值
}
10 内置对象
内置对象就是指 JS 语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法)
JavaScript 提供了多个内置对象:Math、 Date 、Array、String等
10.1 Math对象
Math 对象不是构造函数,它具有数学常数和函数的属性和方法。跟数学相关的运算(求绝对值,取整、最大值等)可以使用 Math 中的成员。
Math.PI // 圆周率
Math.floor() // 向下取整
Math.ceil() // 向上取整
Math.round() // 四舍五入版 就近取整 注意 -3.5 结果是 -3
Math.abs() // 绝对值
Math.max()/Math.min() // 求最大和最小值
10.1.1 随机数方法 random()
random() 方法可以随机返回一个小数,其取值范围是 [0,1),左闭右开 0 <= x < 1
得到一个两数之间的随机整数,包括两个数在内
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
10.2 日期对象
var now = new Date();
如果括号里面有时间,就返回参数里面的时间。例如日期格式字符串为‘2019-5-1’,可以写成new Date(‘2019-5-1’) 或者 new Date(‘2019/5/1’)
日期格式化:
获取日期的总的毫秒形式:
// 实例化Date对象
var now = new Date();
// 1. 用于获取对象的原始值
console.log(date.valueOf())
console.log(date.getTime())
// 2. 简单写可以这么做
var now = + new Date();
// 3. HTML5中提供的方法,有兼容性问题
var now = Date.now();
11 操作DOM
11.1 DOM简介
- 文档:一个页面就是一个文档,DOM 中使用 document 表示
- 元素:页面中的所有标签都是元素,DOM 中使用 element 表示
- 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM 中使用 node 表示
DOM 把以上内容都看做是对象
11.2 获取页面元素
获取页面中的元素可以使用以下几种方式:
- 根据 ID 获取
- 根据标签名获取
- 通过 HTML5 新增的方法获取
- 特殊元素获取
11.2.1 根据id获取
使用 getElementById() 方法可以获取带有 ID 的元素对象。
document.getElementById('id');
使用 console.dir() 可以打印我们获取的元素对象,更好的查看对象里面的属性和方法。
11.2.2 根据标签名获取
使用 getElementsByTagName() 方法可以返回带有指定标签名的对象的集合。
document.getElementsByTagName('标签名');
注意:
- 因为得到的是一个对象的集合,所以我们想要操作里面的元素就需要遍历。
- 得到元素对象是动态的
- 如果获取不到元素,则返回为空的伪数组(因为获取不到对象)
还可以获取某个元素(父元素)内部所有指定标签名的子元素.
element.getElementsByTagName('标签名');
注意:父元素必须是单个对象(必须指明是哪一个元素对象). 获取的时候不包括父元素自己。
11.2.3 通过 HTML5 新增的方法获取
1. document.getElementsByClassName(‘类名’);// 根据类名返回元素对象集合
2. document.querySelector('选择器'); // 根据指定选择器返回第一个元素对象
3. document.querySelectorAll('选择器'); // 根据指定选择器返回
注意:
querySelector 和 querySelectorAll里面的选择器需要加符号,比如:document.querySelector(‘#nav’);
11.2.4 classList 属性
classList属性是HTML5新增的一个属性,返回元素的类名。但是ie10以上版本支持。
该属性用于在元素中添加,移除及切换 CSS 类。
11.2.4.1 添加类
element.classList.add(’类名’):
11.2.4.2 移除类
element.classList.add(’类名’):
11.2.4.3 切换类
element.classList.toggle(’类名’):
注意:以上方法里面,所有类名都不带点
11.2.5 获取特殊元素(body,html)
doucumnet.body // 返回body元素对象
document.documentElement // 返回html元素对象
11.3 事件
11.3.1 常见的鼠标事件
- 禁止鼠标右键菜单
contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
})
- 禁止鼠标选中(selectstart 开始选中)
document.addEventListener('selectstart', function(e) {
e.preventDefault();
})
- mouseenter 和mouseover的区别
- 当鼠标移动到元素上时就会触发 mouseenter 事件
- 类似 mouseover,它们两者之间的差别是
- mouseover 鼠标经过自身盒子会触发,经过子盒子还会触发。 mouseenter 只会经过自身盒子触发
- 之所以这样,就是因为mouseenter不会冒泡
- 跟mouseenter搭配 鼠标离开 mouseleave 同样不会冒泡
11.3.2 常用的键盘事件
注意: onkeydown 和 onkeyup 不区分字母大小写,onkeypress 区分字母大小写。
在实际开发中,更多的使用keydown和keyup, 它能识别所有的键(包括功能键)
Keypress 不识别功能键,但是keyCode属性能区分大小写,返回不同的ASCII值
11.3.3 注册事件(绑定事件)
给元素添加事件,称为注册事件或者绑定事件。
注册事件有两种方式:传统方式和方法监听注册方式
11.3.3.1 addEventListener 事件监听方式
eventTarget.addEventListener(type, listener[, useCapture])
将指定的监听器注册到 eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。
- type:事件类型字符串,比如 click 、mouseover ,注意这里不要带 on
- listener:事件处理函数,事件发生时,会调用该监听函数
- useCapture:可选参数,是一个布尔值,默认是 false。
11.3.3.2 attachEvent 事件监听方式
eventTarget.attachEvent(eventNameWithOn, callback)
将指定的监听器注册到 eventTarget(目标对象) 上,当该对象触发指定的事件时,指定的回调函数就会被执行。
- eventNameWithOn:事件类型字符串,比如 onclick 、onmouseover ,这里要带 on
- callback: 事件处理函数,当目标触发事件时回调函数被调用
注意:IE8 及早期版本支持
11.3.4 删除事件(解绑事件)
1. 传统注册方式
eventTarget.onclick = null;
2. 方法监听注册方式
① eventTarget.removeEventListener(type, listener[, useCapture]);
② eventTarget.detachEvent(eventNameWithOn, callback);
11.3.5 DOM 事件流
事件流描述的是从页面中接收事件的顺序。
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即 DOM 事件流。
比如我们给一个div 注册了点击事件:
DOM 事件流分为3个阶段:
- 捕获阶段
- 当前目标阶段
- 冒泡阶段
事件冒泡: IE 最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程。
事件捕获: 网景最早提出,由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程。
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即 DOM 事件流。
注意:
- JS 代码中只能执行捕获或者冒泡其中的一个阶段。
- onclick 和 attachEvent 只能得到冒泡阶段。
- addEventListener(type, listener[, useCapture])第三个参数如果是 true,表示在事件捕获阶段调用事件处理程序;如果是 false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序。
- 实际开发中我们很少使用事件捕获,我们更关注事件冒泡。
- 有些事件是没有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave
- 事件冒泡有时候会带来麻烦,有时候又会帮助很巧妙的做某些事件。
11.3.6
eventTarget.onclick = function(event) {}
eventTarget.addEventListener('click', function(event) {})
// 这个 event 就是事件对象,我们还喜欢的写成 e 或者 evt
官方解释:event 对象代表事件的状态,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态。
11.3.6.1 事件对象本身的获取存在兼容问题:
- 标准浏览器中是浏览器给方法传递的参数,只需要定义形参 e 就可以获取到。
- 在 IE6~8 中,浏览器不会给方法传递参数,如果需要的话,需要到 window.event 中获取查找。
解决:
e = e || window.event;
11.3.6.2 事件对象的常见属性和方法
e.target 和 this 的区别:
- this 是事件绑定的元素, 这个函数的调用者(绑定这个事件的元素)
- e.target 是事件触发的元素。
11.3.7 阻止事件冒泡
事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点。
事件冒泡本身的特性,会带来的坏处,也会带来的好处
- 标准写法:利用事件对象里面的 stopPropagation()方法
e.stopPropagation()
- 非标准写法:IE 6-8 利用事件对象 cancelBubble 属性
e.cancelBubble = true;
11.3.8 事件委托(代理、委派)
事件冒泡本身的特性,会带来的坏处,也会带来的好处
例子:
<ul>
<li>点击出现对话框</li>
<li>点击出现对话框</li>
<li>点击出现对话框</li>
<li>点击出现对话框</li>
<li>点击出现对话框</li>
</ul>
//点击每个 li 都会弹出对话框,以前需要给每个 li 注册事件,是非常辛苦的,而且访问 DOM 的次数越多,这就会延长整个页面的交互就绪时间。
事件委托
事件委托也称为事件代理, 在 jQuery 里面称为事件委派。
事件委托的原理
不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
以上案例:给 ul 注册点击事件,然后利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上, ul 有注册事件,就会触发事件监听器。
事件委托的作用
我们只操作了一次 DOM ,提高了程序的性能。
11.4 操作元素
JavaScript 的 DOM 操作可以改变网页内容、结构和样式,我们可以利用 DOM 操作元素来改变元素里面的内容 、属性等。注意以下都是属性
11.4.1 改变元素内容
// 从起始位置到终止位置的内容, 但它去除 html 标签, 同时空格和换行也会去掉
element.innerText
//起始位置到终止位置的全部内容,包括 html 标签,同时保留空格和换行
element.innerHTML
src、href、id、alt、title等
11.4.2 表单元素的属性操作
利用 DOM 可以操作如下表单元素的属性:
type、value、checked、selected、disabled
11.4.3 样式属性操作
我们可以通过 JS 修改元素的大小、颜色、位置等样式。
1. element.style 行内样式操作
2. element.className 类名样式操作
注意:
- JS 里面的样式采取驼峰命名法 比如 fontSize、 backgroundColor
- JS 修改 style 样式操作,产生的是行内样式,CSS 权重比较高
- className 会直接更改元素的类名,会覆盖原先的类名。
11.4.4 小结
11.4.5 自定义属性的操作
获取属性值:
element.属性 获取属性值。(元素本身自带的属性)
element.getAttribute(‘属性’); 主要获得自定义的属性 (标准)自定义的属性
设置属性值:
element.属性 = ‘值’ 设置内置属性值。
element.setAttribute(‘属性’, ‘值’); 主要设置自定义的属性 (标准)
移除属性
element.removeAttribute(‘属性’);
11.4.6 H5自定义属性
自定义属性目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。
自定义属性获取是通过getAttribute(‘属性’) 获取。
但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性。
11.4.6.1 设置H5自定义属性
H5规定自定义属性data-开头做为属性名并且赋值。
比如 <div data-index=“1”></div>
或者使用 JS 设置
element.setAttribute(‘data-index’, 2)
11.4.6.2 获取H5自定义属性
兼容性获取 element.getAttribute(‘data-index’);
H5新增 element.dataset.index 或者 element.dataset[‘index’] ie 11才开始支持
11.5 操作节点
11.5.1 父级节点
node.parentNode
parentNode 属性可返回某节点的父节点,注意是最近的一个父节点
如果指定的节点没有父节点则返回 null
11.5.2 子节点
parentNode.childNodes(标准)
`返回包含指定节点的子节点的集合,该集合为即时更新的集合。
注意:返回值里面包含了所有的子节点,包括元素节点,文本节点等。
如果只想要获得里面的元素节点,则需要专门处理。 所以一般不提倡使用childNodes`
parentNode.children(非标准)
`是一个只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回。
虽然children 是一个非标准,但是得到了各个浏览器的支持,因此可以放心使用`
parentNode.firstChild
`返回第一个子节点,找不到则返回null。包含所有的节点(包含后代)。`
parentNode.lastChild
`返回最后一个子节点,找不到则返回null。包含所有的节点(包含后代)。`
parentNode.firstElementChild
`返回第一个子元素节点,找不到则返回null。`
parentNode.lastElementChild
`返回最后一个子元素节点,找不到则返回null。`
注意:这两个方法有兼容性问题,IE9 以上才支持。
实际开发中,firstChild 和 lastChild 包含其他节点,操作不方便,而 firstElementChild 和 lastElementChild 又有兼容性问题,那如何获取第一个子元素节点或最后一个子元素节点呢?
解决方案:
如果想要第一个子元素节点,可以使用 parentNode.chilren[0]
如果想要最后一个子元素节点,可以使用 parentNode.chilren[parentNode.chilren.length - 1]
11.5.3 兄弟节点
node.nextSibling
`返回当前元素的下一个兄弟元素节点,找不到则返回null。同样,也是包含所有的节点。`
node.previousSibling
`返回当前元素上一个兄弟元素节点,找不到则返回null。同样,也是包含所有的节点。`
node.nextElementSibling
`返回当前元素下一个兄弟元素节点,找不到则返回null。`
node.previousElementSibling
`返回当前元素上一个兄弟节点,找不到则返回null。 `
注意:这两个方法有兼容性问题, IE9 以上才支持。
11.5.4 创建节点
document.createElement('tagName')
`创建由 tagName 指定的 HTML 元素。因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称为动态创建元素节点。`
node.appendChild(child)
`将一个节点添加到指定父节点的子节点列表末尾。类似于 CSS 里面的 after 伪元素。`
node.insertBefore(child, 指定元素)
`将一个节点添加到父节点的指定子节点前面。类似于 CSS 里面的 before 伪元素。`
11.5.5 删除节点
node.removeChild(child)
从 DOM 中删除一个子节点,返回删除的节点。
11.5.6 复制节点(克隆节点)
node.cloneNode()
返回调用该方法的节点的一个副本。 也称为克隆节点/拷贝节点
如果括号参数为空或者为 false ,只克隆复制节点本身,不克隆里面的子节点。
如果括号参数为 true ,会复制节点本身以及里面所有的子节点。
11.5.7 三种动态创建元素区别
document.write()
element.innerHTML
document.createElement()
- document.write 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
- innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘
- innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
- createElement() 创建多个元素效率稍低一点点,但是结构更清晰
总结:不同浏览器下,innerHTML 效率要比 creatElement 高
12 操作BOM
12.1 BOM概述
BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window。
BOM 由一系列相关的对象构成,并且每个对象都提供了很多方法与属性。
BOM 缺乏标准,JavaScript 语法的标准化组织是 ECMA,DOM 的标准化组织是 W3C,BOM 最初是Netscape 浏览器标准的一部分。
组成:
window 对象是浏览器的顶级对象,它具有双重角色。
- 它是 JS 访问浏览器窗口的一个接口。
- 它是一个全局对象。定义在全局作用域中的变量、函数都会变成 window 对象的属性和方法。
在调用的时候可以省略 window,对话框也属于 window 对象方法,如 alert()、prompt() 等。
注意:window下的一个特殊属性 window.name
12.2 window 对象的常见事件
12.2.1 窗口加载事件
窗口 (页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS 文件等), 就调用的处理函数。
window.onload = function(){}
或者
window.addEventListener("load",function(){});
注意:
- 有了 window.onload 就可以把 JS 代码写到页面元素的上方,因为 onload 是等页面内容全部加载完毕,再去执行处理函数。
- window.onload 传统注册事件方式 只能写一次,如果有多个,会以最后一个 window.onload 为准。
- 如果使用 addEventListener 则没有限制
document.addEventListener('DOMContentLoaded',function(){})
DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等。
Ie9以上才支持
如果页面的图片很多的话, 从用户访问到onload触发可能需要较长的时间, 交互效果就不能实现,必然影响用户的体验,此时用 DOMContentLoaded 事件比较合适。
12.2.2 调整窗口大小事件
window.onresize = function(){}
window.addEventListener("resize",function(){});
注意:
- 只要窗口大小发生像素变化,就会触发这个事件。
- 经常利用这个事件完成响应式布局。 window.innerWidth 当前屏幕的宽度
12.3 定时器
window 对象提供了 2 个非常好用的方法-定时器。
- setTimeout()
- setInterval()
12.3.1 setTimeout() 定时器
window.setTimeout(调用函数, [延迟的毫秒数]);
window 可以省略。
延迟的毫秒数省略默认是 0,单位是毫秒。
因为定时器可能有很多,所以我们经常给定时器赋值一个标识符。
12.3.2 停止 setTimeout() 定时器
//setInterval() 方法重复调用一个函数,每隔这个时间,就去调用一次回调函数。
window.clearTimeout(timeoutID)
clearTimeout()方法取消了先前通过调用 setTimeout() 建立的定时器。
里面的参数就是定时器的标识符 。
12.3.4 setInterval() 定时器
//setInterval() 方法重复调用一个函数,每隔这个时间,就去调用一次回调函数。
window.setInterval(回调函数, [间隔的毫秒数]);
window 可以省略。
延迟的毫秒数省略默认是 0,单位是毫秒。
因为定时器可能有很多,所以我们经常给定时器赋值一个标识符。
12.3.5 停止setInterval() 定时器
window.clearInterval(intervalID);
clearInterval()方法取消了先前通过调用 setInterval()建立的定时器。
里面的参数就是定时器的标识符 。
12.4 JS执行队列
12.4.1 JS 是单线程
JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。这是因为 Javascript 这门脚本语言诞生的使命所致——JavaScript 是为处理页面中用户的交互,以及操作 DOM 而诞生的。比如我们对某个 DOM 元素进行添加和删除操作,不能同时进行。 应该先进行添加,之后再删除。
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。这样所导致的问题是: 如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
为了解决这个问题,利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程。于是,JS 中出现了同步和异步。
同步任务:
同步任务都在主线程上执行,形成一个执行栈。
异步任务:
JS 的异步是通过回调函数实现的。
一般而言,异步任务有以下三种类型:
- 普通事件,如 click、resize 等
- 资源加载,如 load、error 等
- 定时器,包括 setInterval、setTimeout 等
异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)。
12.4.2 JS 执行机制
- 先执行执行栈中的同步任务。
- 异步任务(回调函数)放入任务队列中。
- 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环( event loop)。
12.5 location 对象
window 对象给我们提供了一个 location 属性用于获取或设置窗体的 URL,并且可以用于解析 URL 。 因为这个属性返回的是一个对象,所以我们将这个属性也称为 location 对象。
12.5.1 URL
统一资源定位符 (Uniform Resource Locator, URL) 是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
URL 的一般语法格式为:
protocol://host[:port]/path/[?query]#fragment
http://www.baidu.cn/index.html?name=zhangsan&age=23#link
12.5.2 location 对象的属性
12.5.3 location 对象的方法
12.6 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 = ""; //电脑
}
12.7 history 对象
window 对象给我们提供了一个 history 对象,与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的 URL。
12.8 本地存储
随着互联网的快速发展,基于网页的应用越来越普遍,同时也变的越来越复杂,为了满足各种各样的需求,会经常性在本地存储大量的数据,HTML5规范提出了相关解决方案。
本地存储特性:
- 数据存储在用户浏览器中
- 设置、读取方便、甚至页面刷新不丢失数据
- 容量较大,sessionStorage约5M、localStorage约20M
- 只能存储字符串,可以将对象JSON.stringify() 编码后存储
12.8.1 window.sessionStorage
- 生命周期为关闭浏览器窗口
- 在同一个窗口(页面)下数据可以共享
- 以键值对的形式存储使用
12.8.1.1 存储数据
sessionStorage.setItem(key, value)
12.8.1.2 获取数据
sessionStorage.getItem(key)
12.8.1.3 删除数据
sessionStorage.removeItem(key)
12.8.1.4 删除所有数据
sessionStorage.clear()
12.8.1 window.localStorage
- 声明周期永久生效,除非手动删除 否则关闭页面也会存在
- 可以多窗口(页面)共享(同一浏览器可以共享)
- 以键值对的形式存储使用
12.8.1.1 存储数据
localStorage.setItem(key, value)
12.8.1.2 获取数据
localStorage.getItem(key)
12.8.1.3 删除数据
localStorage.removeItem(key)
12.8.1.4 删除所有数据
localStorage.clear()
13 JS网页特效
13.1 元素偏移量 offset
offset 翻译过来就是偏移量, 我们使用 offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
- 获得元素距离带有定位父元素的位置
- 获得元素自身的大小(宽度高度)
注意: 返回的数值都不带单位
offset 与 style 区别
13.2 元素可视区 client
client 翻译过来就是客户端,我们使用 client 系列的相关属性来获取元素可视区的相关信息。通过 client 系列的相关属性可以动态的得到该元素的边框大小、元素大小等。
13.3 元素滚动 scroll
scroll 翻译过来就是滚动的,我们使用 scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等。
如果浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条。当滚动条向下滚动时,页面上面被隐藏掉的高度,我们就称为页面被卷去的头部。滚动条在滚动时会触发 onscroll 事件。
注意:页面滚动的距离通过 window.pageXOffset 获得
13.4 动画函数封装
13.4.1 动画实现原理
核心原理:通过定时器 setInterval() 不断移动盒子位置。
实现步骤:
- 获得盒子当前位置
- 让盒子在当前位置加上1个移动距离
- 利用定时器不断重复这个操作
- 加一个结束定时器的条件
- 注意此元素需要添加定位,才能使用element.style.left
13.4.2 动画函数简单封装
注意函数需要传递2个参数,动画对象和移动到的距离。
13.4.3 动画函数给不同元素记录不同定时器
如果多个元素都使用这个动画函数,每次都要var 声明定时器。我们可以给不同的元素使用不同的定时器(自己专门用自己的定时器)。
核心原理:利用 JS 是一门动态语言,可以很方便的给当前对象添加属性。
13.4.4 缓动效果原理
缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来
思路:
- 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来。
- 核心算法: (目标值 - 现在的位置 ) / 10 做为每次移动的距离 步长
- 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
- 注意步长值需要取整
13.4.5 动画函数多个目标值之间移动
可以让动画函数从 800 移动到 500。
当我们点击按钮时候,判断步长是正值还是负值
- 如果是正值,则步长 往大了取整
- 如果是负值,则步长 向小了取整
13.4.6 动画函数添加回调函数
回调函数原理:函数可以作为一个参数。将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调。
回调函数写的位置:定时器结束的位置。
13.4.7 动画函数封装到单独JS文件里面
因为以后经常使用这个动画函数,可以单独封装到一个JS文件里面,使用的时候引用这个JS文件即可。
- 单独新建一个JS文件。
- HTML文件引入 JS 文件。
13.5 节流阀
防止轮播图按钮连续点击造成播放过快。
节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。
核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。
开始设置一个变量 var flag = true;
If(flag) {flag = false; do something} 关闭水龙头
利用回调函数 动画执行完毕, flag = true 打开水龙头
14 JS移动端
14.1 触屏事件
14.1.1 概述
移动端浏览器兼容性较好,我们不需要考虑以前 JS 的兼容性问题,可以放心的使用原生 JS 书写效果,但是移动端也有自己独特的地方。比如触屏事件 touch(也称触摸事件),Android 和 IOS 都有。
touch 对象代表一个触摸点。触摸点可能是一根手指,也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。
常见的触屏事件如下:
14.1.2 触摸事件对象(TouchEvent)
TouchEvent 是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多个触点,使开发者可以检测触点的移动,触点的增加和减少,等等
touchstart、touchmove、touchend 三个事件都会各自有事件对象。
触摸事件对象重点我们看三个常见对象列表:
14.1.3 移动端拖动元素
- touchstart、touchmove、touchend 可以实现拖动元素
- 但是拖动元素需要当前手指的坐标值 我们可以使用 targetTouches[0] 里面的pageX 和 pageY
- 移动端拖动的原理: 手指移动中,计算出手指移动的距离。然后用盒子原来的位置 + 手指移动的距离
- 手指移动的距离: 手指滑动中的位置 减去 手指刚开始触摸的位置
拖动元素三步曲:
(1) 触摸元素 touchstart: 获取手指初始坐标,同时获得盒子原来的位置
(2) 移动手指 touchmove: 计算手指的滑动距离,并且移动盒子
(3) 离开手指 touchend:
注意: 手指移动也会触发滚动屏幕所以这里要阻止默认的屏幕滚动 e.preventDefault();
14.2 移动端常用开发插件
移动端常见插件:iScroll、Swiper、SuperSlider 。
Swiper 插件:中文官网地址: https://www.swiper.com.cn/
iScroll 插件:https://github.com/cubiq/iscroll
SuperSlider 插件:http://www.superslide2.com/
视频插件 zy.media.js:
H5 给我们提供了 video 标签,但是浏览器的支持情况不同。在移动端我们可以使用插件方式来制作。
14.3 移动端click 延时解决方案
移动端 click 事件会有 300ms 的延时,原因是移动端屏幕双击会缩放(double tap to zoom) 页面。
3种解决方案:
- 禁用缩放。 浏览器禁用默认的双击缩放行为并且去掉 300ms 的点击延迟。
<meta name="viewport" content="user-scalable=no">
- 利用touch事件自己封装这个事件解决 300ms 延迟。
原理就是:
1) 当我们手指触摸屏幕,记录当前触摸时间
2) 当我们手指离开屏幕, 用离开的时间减去触摸的时间
3) 如果时间小于150ms,并且没有滑动过屏幕, 那么我们就定义为点击
//封装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(){ // 执行代码 });
- 使用插件。 fastclick 插件解决 300ms 延迟。
document.addEventListener('DOMContentLoaded',function () {
/*等页面文档加载完成 不需要等所有的资源*/
FastClick.attach(document.body);
});
14.4 移动端常用开发框架
Bootstrap、Vue(UniApp、Vant)、Angular
MUI 原生UI前端框架:http://dev.dcloud.net.cn/mui/