前端的修行之路-javaScript
javaScript
输入输出语句
-
alert(msg)
:浏览器弹出警示框。 -
console.log(msg)
:浏览器控制台打印输出信息。 -
prompt(info)
:浏览器弹出输入框,用户可以输入。
变量
变量是内存里的一块空间,用来存储数据。
注意事项
- 通常用var关键词来声明变量。
- 一个变量被重新赋值后,它原有的值就会被覆盖,变量值将以最后一次赋的值为准。
- 同时声明多个变量时,只需要写一个var,多个变量名之间使用英文逗号隔开。
命名规范
- 由字母(A-Za-z)、数字(0-9)、下划线(_)、美元符号($)组成。
- 严格区分大小写。
- 不能以数字开头。
- 不能是关键字、保留字。
- 变量名必须有意义。
- 遵守驼峰命名法。首字母小写,后面单词的首字母需要大写。
数据类型
简单数据类型
- 简单类型又叫做基本数据类型或者值类型。
- 值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型。
- 栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。简单数据类型存放到栈里面。
- 简单类型传参:函数的形参也是看做是一个变量,当把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到的外部变量。
Number
Number:数字型,包含整型值和浮点型值。默认值为0。
- 八进制:数字前加0,范围为0~7。
- 十六进制:数字前加0x,范围为09和af。
Number.MAX_VALUE
:数值的最大值(1.7976931348623157e+308)。Number.MIN_VALUE
:数值的最大值(5e-324)。Infinity
:代表无穷大,大于任何数值。-Infinity
:代表无穷小,小于任何数值。NaN
:Not a number,代表一个非数值。isNaN
:判断非数字。如果是数字为false,否则为true。
String
String:字符串类型,字符串都带引号。默认值为""。
- 字符串嵌套:可以用单引号嵌套双引号,或者用双引号嵌套单引号(外双内单,外单内双)。
- 字符串转义符:都是\开头的。
- 字符串拼接:可以使用+进行拼接,其拼接方式为字符串+任何类型=拼接之后的新字符串。
转义符 | 解释说明 |
---|---|
\n | 换行符 |
\ | 斜杠 |
’ | 单引号 |
" | 双引号 |
\t | tab缩进 |
\b | 空格 |
str.length
:获取整个字符串的长度。
Boolean
Boolean:布尔值类型,如true、false,等价于1和0。默认值为false。
Undefined
undefined:没有赋值。默认值为undefined。
- undefined和数字相加,结果是NaN。
Null
null:空值。默认值为null。
- null和数字相加,结果是数字。
获取变量数据类型
typeof
:可用来获取检测变量的数据类型。
数据类型的转换
字符串的转换
- 使用
num.toString()
转成字符串。 - 使用
String()
强制转换成字符串。 - 和字符串拼接转换成字符串。
数字型的转换
- 使用
parseInt(String)
将string类型转成整数数值型。 - 使用
parseFloat(string)
将string类型转成浮点数数值型。 - 使用
Number()
强制将string类型转成数值型。 - 利用算术运算隐式转换为数值型。
- 如果前面为数字,后面是非数字,转换时,只保留数字。
- 如果前面为非数字,后面为数字,转换的结果是NaN。
布尔型的转换
-
使用
Boolean()
强制将其他类型转成布尔值 -
代表空、否定的值会被转换为false,如’’、0、NaN、null、undefined。
-
其余值都会被转换为true。
复杂数据类型
- 复杂类型又叫做引用类型。
- 引用类型:复杂数据类型,在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型。
- 堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。复杂类型存放到堆里面。
- 复杂类型传参:函数的形参也是看做是一个变量,当把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
运算符
运算符也被称为操作符,是用于实现复制、比较和执行算数运算等功能的符号。
常用的运算符有:算数运算符、递增和递减运算符、比较运算符、逻辑运算符、赋值运算符。
算数运算符
运算符 | 描述 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
% | 取余数(取模) |
- 进行算术计算时,浮点数精确度远远不如整数。
- 不要直接判断两个浮点数是否相等。
递增和递减运算符
递增(++)和递减(–)既可以放在变量前面,也可以放在变量后面。放在变量前面时,称为前置递增(递减)运算符,放在变量后面时,称为后置递增(递减)运算符。
- 递增和递减运算符必须和变量配合使用。
- 前置递增(递减),先自加(自减),后返回值。
- 后置递增(递减),先返回值),后自加(自减)。
比较运算符
比较运算符是两个数据进行比较时所使用的运算符,比较运算后,会返回一个布尔值作为比较运算的结果。
运算符名称 | 说明 |
---|---|
< | 小于号 |
> | 大于号 |
>= | 大于等于号 |
<= | 小于等于号 |
== | 判等号(会转型) |
!= | 不等号 |
=== !== | 全等 要求值和数据类型都一致 |
逻辑运算符
逻辑运算符是用来进行布尔值运算的运算符,其返回值也是布尔值。
逻辑运算符 | 说明 |
---|---|
&& | 逻辑与,简称与(and),两边都是true才为true |
|| | 逻辑或,简称或(or),两边都是false才为false |
! | 逻辑非,简称非(not),取反 |
- 短路运算的原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式值。
- 逻辑与的短路运算:如果第一个表达式的值为真,则返回表达式2;如果第一个表达式的值为假,则返回表达式1。
- 逻辑或的短路运算:如果第一个表达式的值为真,则返回表达式1;如果第一个表达式的值为假,则返回表达式2。
- 除了0、’’、null、undefined的为假,其余都是真的。
赋值运算符
赋值运算符是用来把数据赋值给变量的运算符。
赋值运算符 | 说明 |
---|---|
= | 直接赋值 |
+=、-= | 加、减一个数后在赋值 |
*=、/=、%= | 乘、除、取模后在赋值 |
运算符优先级
运算符 | 顺序 |
---|---|
小括号 | () |
一元运算符 | ++ – ! |
算数运算符 | 先* / %后+ - |
关系运算符 | > >= < <= |
相等运算符 | == != === !== |
逻辑运算符 | 先&&后|| |
赋值运算符 | = |
逗号运算符 | , |
函数
函数就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。
函数的使用
函数在使用时分为两步:声明函数和调用函数。
函数的声明
//声明函数
function 函数名() {
//函数体代码
}
- function是声明函数的关键字,必须小写。
- 由于函数一般是为了实现某个功能才定义的,所以通常我们将函数名命名为动词。
var fun = function() {
//函数体
}
- fun是变量名,不是函数名。
- 函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值,而函数表达式里存的是函数。
- 函数表达式也可以进行传递参数。
函数的调用
//调用函数
函数名(); //通过调用函数名来执行函数体代码
- f调用的时候千万不要忘记添加小括号。
- 声明函数本身并不会执行代码,只有调用函数时才会执行函数体代码。
函数的封装
函数的封装是把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口。
函数参数
function 函数名(形参) {
//函数体
}
函数名(实参);
- 在声明函数时,可以在函数名称后面的小括号中添加一些参数,这些参数被称为形参。
- 在调用函数时,同样也需要传递相应的参数,这些参数被称为实参。
- 多个参数中间用逗号分隔。
- 参数的作用是在函数内部某些值不能固定,我们可以通过参数在调用函数时传递不同的值进去。
参数个数 | 说明 |
---|---|
实参个数等于形参个数 | 输出正确结果 |
实参个数多于形参个数 | 只取到形参的个数 |
实参个数小于形参个数多的形参定义为undefined,结果为NaN |
函数返回值
- return语句之后的代码不被执行。
- return只能返回一个值。如果用逗号隔开多个值,以最后一个为准。
- 函数中如果没有return则返回undefined。
arguments使用
- 所有函数都内置了一个arguments对象,arguments对象中存储了传递的所有实参。
- arguments展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点:
- 具有length属性。
- 按索引方式存储数据。
- 不具有数组的push,pop等方法。
作用域
- 作用域:代码名字(变量)在某个范围内起作用和效果,目的是为了提高程序的可靠性,更重要的是减少命名冲突。
- 作用域分为全局作用域和局部作用域。
- 全局作用域:整个script标签或者是一个单独的js文件。
- 局部作用域:在函数内部就是局部作用域,这个代码的名字只在函数内部起效果和作用。
变量的作用域
根据作用域的不同,变量可以分为全局变量和局部变量。
全局变量
在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)。
- 全局变量在代码的任何位置都可以使用。
- 特殊情况下,在函数内不使用var声明的变量也是全局变量(不建议使用)。
局部变量
在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)。
- 局部变量只能在该函数内部使用。
- 函数的形参实际上就是局部变量。
全局变量和局部变量的区别
- 全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存。
- 局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间。
作用域链
- 只要是代码,就至少有一个作用域。
- 写在函数内部的局部作用域。
- 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。
- 根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链。
对象
- 对象是一个具体的事物,看得见摸得着的事物。
- 对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。
- 对象是由属性和方法组成的。属性是事物的特征。方法是事物的行为。
对象的创建
- 利用字面量创建对象。
- 利用new Object创建对象。
- 利用构造函数创建对象。
利用字面量创建对象
var obj = {
name: 'Freedom',
age: 18,
sex: '男',
say: function() {
console.log('hello');
}
}
- 属性对象字面量:就是花括号{}里面包含了表达这个具体事物(对象)的属性和方法。
- {}里面采取键值对的形式表示。键相当于属性名。值相当于属性值**,可以是任意类型的值(数字类型、字符串类型、布尔类型,函数类型等)。
- 对象里面的属性调用:
对象.属性名
。 - 对象里面属性的另一种调用方式:
对象['属性名']
,注意方括号里面的属性必须加引号。 - 对象里面的方法调用:
对象.方法名()
,注意这个方法名字后面一定加括号。
利用new Object创建对象
- 跟数组的
new Array()
原理一致。
var obj = new Object();
obj.name = 'Freedom',
obj.age = 18,
obj.sex = '男',
obj.say = function() {
console.log('hello');
}
利用构造函数创建对象
- 构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new运算符一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
function 构造函数名() {
this.属性 = 值;
this.方法 = function() {}
}
new 构造函数名();
- 构造函数名字首字母要大写。
- 构造函数不需要return就可以返回结果。
- 调用构造函数必须使用new。
- 构造函数,抽象了对象的公共部分,封装到了函数里面,它泛指某一大类。
- 创建对象,特指某一个,通过new关键字创建对象的过程我们也称为对象实例化。
变量、属性、函数、方法的总结
- 变量:单独声明赋值,单独存在。
- 属性:对象里面的变量称为属性,不需要声明,用来描述该对象的特征。
- 函数:单独存在,通过
函数名()
的方式就可以调用。 - 方法:对象里面的函数称为方法,方法不需要声明,使用
对象.方法名()
的方式就可以调用,方法用来描述该对象的行为和功能。
遍历对象属性
- for…in语句用于对数组或者对象的属性进行循环操作。
var obj = {
name: 'Freedom',
age: 18,
sex: '男',
say: function() {
console.log('hello');
}
}
for (var key in obj) {
console.log(key); //输出属性名
console.log(obj[key]); //输出属性值
}
内置对象
- javascript中的对象分为3种:自定义对象、内置对象、浏览器对象。
- 自定义对象和内置对象是属于ECMAScript;浏览器对象属于javascript独有的。
- 内置对象就是指javascript语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法)。
- javascript提供了多个内置对象:Math、Date、Array、String等。
Math对象
Math.PI
:圆周率。Math.floor()
:向下取整。Math.ceil()
:向上取整。Math.round()
:四舍五入,就近取整。Math.abs()
:绝对值。Math.max()/Math.min()
:求最大和最小值。Math.random()
:随机数。
Date对象
- Date对象和Math对象不一样,它是一个构造函数,需要实例化后才能使用。
- Date实例用来处理日期和时间。
Date对象的实例化
var now = new Date(); //获取当前的时间
var dateTime = new Date('2019-5-1'); //获取参数里的时间
日期格式化的获取
方法名 | 说明 |
---|---|
getFullYear() | 获取当年 |
getMonth() | 获取当月(0-11) |
getDate() | 获取当天日期 |
getDay() | 获取星期几(周日0到周六6) |
getHours() | 获取当前小时 |
getMinutes() | 获取当前分钟 |
getSeconds() | 获取当前秒钟 |
getTime()/valueOf()/+new Date()/Date.now() | 获取总的毫秒 |
Array对象
数组的创建
var arr = []; //空数组
var arr = new Array(); //空数组
var arr = new Array(2); //长度为2的数组
var arr = new Array(2,3); //长度为2,值为2,3的数组
数组的检测
参数 instanceof Array
Array.isArray(参数) //只支持IE9以上版本
数组元素的添加删除
方法名 | 说明 |
---|---|
push(parm) | 末尾添加一个或多个元素,注意修改原数组 |
pop() | 删除数组最后一个元素,把数组长度减1无参数、修改原数组 |
unshift(parm) | 向数组的开头添加一个或更多元素,注意修改原数组 |
shift() | 删除数组的第一个元素,数组长度减1无参数、修改原数组 |
数组的排序
方法名 | 说明 |
---|---|
reverse() | 颠倒数组中元素的顺序,无参数 |
sort() | 对数组的元素进行排序 |
获取数组的索引
方法名 | 说明 |
---|---|
indexOf() | 数组中查找给定元素的第一个索引 |
lastIndexOf() | 在数组中的最后一个的索引 |
数组转换为字符串
方法名 | 说明 |
---|---|
toString() | 把数组转换成字符串,逗号分隔每一项 |
join(‘分隔符’) | 方法用于把数组中的所有元素转换为一个字符串 |
数组的改变
方法名 | 说明 |
---|---|
concat() | 连接两个或多个数组,不影响原数组 |
skice() | 数组截取slice(begin,end) |
splice() | 数组删除splice(第几个开始,要删除个数) |
字符串对象
-
基本包装类型就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法。
-
字符串的不可变指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中开辟了一个内存空间。
返回字符的位置
方法名 | 说明 |
---|---|
indexOf(str,strPos) | 返回指定内容在字符串中的位置,如果找不到就返回-1,开始的位置就是index索引号 |
lastIndexOf() | 从后往前找,只找第一个匹配 |
根据位置返回字符
方法名 | 说明 |
---|---|
charAt(index) | 返回指定位置的字符(index字符串的索引号) |
charCodeAt(index) | 获取指定位置处字符的ASCII码(index索引号) |
str[index] | 获取指定位置处字符,只支持IE8以上 |
字符串的操作
方法名 | 说明 |
---|---|
concat(str1,str2,str3…) | concat()方法用于连接两个或多个字符串。拼接字符串,等效于+ |
substr(start,length) | 从start位置开始(索引号),length取的个数 |
slice(start,end) | 从start位置开始,截取到end位置,end取不到 |
substring(start,end) | 从start位置开始,截取到end位置,end取不到,基本和slice相同,但是不接受负值 |
replace(‘替换前的字符’,‘替换后的字符’) | 字符的替换 |
split(‘分隔符’) | 字符转换为数组 |
Web API
-
API是给程序员提供的一种工具,以便能更轻松的实现想要完成的功能。
-
Web API是浏览器提供的一套操作浏览器功能和页面元素的API(BOM和DOM)。
DOM
- 文档对象模型(DOM),是W3C组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口。
DOM树
- 文档:一个页面就是一个文档,DOM中使用document表示。
- 元素:页面中的所有标签都是元素,DOM中使用element表示。
- 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示。
获取页面元素
根据ID获取
document.getElementById('id')
:通过id获取,返回一个元素对象。
根据标签名获取
document.getElementsByTagName('tag')
:根据标签名获取,返回带有指定标签名的对象的集合。
通过HTML5新增的方法获取
document.getElementsByClassName('类名')
:根据类名返回元素对象集合。document.querySelector('选择器')
:根据指定选择器返回第一个元素对象。document.querySelectorAll('选择器')
:根据指定选择器返回。
获取特殊元素
document.body
:返回body元素对象。document.documentElement
:返回html元素对象。
操作元素
利用DOM操作元素里面的内容、属性等,可以该表网页内容、结构和样式。
element.innerText
:从起始位置到终止位置的内容,但它去除html标签,同时空格和换行也会去掉。element.innerHTML
:起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行。- 改变元素的属性:如
src
、href
、alt
、title
等。 - 改变表单元素的属性:如
type
、value
、checked
、selected
、disabled
等。 element.style
:改变行内样式操作。element.className
:改变类名样式操作。element.attr
:获取元素本身自带的属性。element.getAttribute(attr)
:主要获得程序员自定义的属性。element.attr=value
:设置内置属性值。element.setAttribute(attr)
:主要设置自定义的属性。element.removeAttribute(attr)
:移除属性。
节点操作
一般地,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。
- 元素节点nodeType为1。
- 属性节点nodeType为2。
- 文本节点nodeType为3(文本节点包含文字、空格、换行等)。
获取节点
node.parentNode
:返回父节点。parentNode.childNodes
:返回包含指定节点的子节点的集合,该集合为即时更新的集合。parentNode.children
:获取所有的子元素节点。parentNode.firstChild
:返回第一个子节点,找不到则返回null。parentNode.lastChild
:返回最后一个子节点,找不到则返回null。parentNode.firstElementChild
:返回第一个子元素节点,找不到则返回null。只支持IE9以上。parentNode.lastElementChild
:返回最后一个子元素节点,找不到则返回null。只支持IE9以上。parentNode.children[index]
:返回子元素节点中的某个元素节点。node.nextSibling
:返回当前元素的下一个兄弟节点,找不到则返回null。包含所有的节点。node.previousSibling
:返回当前元素的上一个兄弟节点,找不到则返回null。包含所有的节点。node.nextElementSibling
:返回当前元素的下一个兄弟元素节点,找不到则返回null。只支持IE9以上。node.previousElementSibling
:返回当前元素的上一个兄弟元素节点,找不到则返回null。包含所有的节点。只支持IE9以上。
创建节点
document.createElement('tagName')
:动态创建元素节点。
添加节点
node.appendChild(child)
:将一个节点添加到指定父节点的子节点列表末尾。node.insertBefore(child,指定元素)
:将一个节点添加到父节点的指定子节点前面。element.insertAdjacentHTML(position, text)
:将指定的文本解析为HTML,并将结果节点插入到DOM树中。beforebegin
: 元素自身的前面。afterbegin
: 插入元素内部的第一个子节点之前。beforeend
: 插入元素内部的最后一个子节点之后。afterend
: 元素自身的后面。
删除节点
node.removeChild(child)
:返回删除的节点。
补充:阻止链接跳转需要添加javascript:void(0)
或者javascript:;
。
复制节点
node.cloneNode()
:返回调用该方法的节点的一个副本。
注意:如果括号参数为空或者为false,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点;括号参数为true,则是深度拷贝,会复制节点本身以及里面所有的子节点。
三种动态创建元素区别
document.write()
是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘。element.innerHTML()
是将内容写入某个DOM节点,不会导致页面全部重绘。element.innerHTML()
创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂。document.creatElement()
创建多个元素效率稍微低一点点,但是结构更清晰
总结:不同浏览器下,innerHTML效率要比createElement高。
事件
事件是由三部分组成:事件源、事件类型和事件处理程序。
- 事件源:事件被触发的对象。
- 事件类型:如何触发。
- 事件处理程序:通过一个函数赋值的方式。
常见的鼠标事件
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击左键触发 |
onmouseover | 鼠标经过触发(不仅自身,子盒也会) |
onmouseenter | 鼠标经过触发(自身) |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
注册事件
-
给元素添加事件,称为注册事件或者绑定事件。
-
注册事件有两种方式:传统方式和方法监听注册方式。
传统注册方式
- 利用on开头的事件onclick。
<button onclick="alert("hi")"></button>
。btn.onclick=function(){}
。- 特点:注册事件的唯一性。
- 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数。
方法监听注册方式
- w3c标准推荐方式。
addEventListener()
它是一个方法。- IE9之前的IE不支持此方法,可使用
attachEvent()
代替。 - 特点:同一个元素同一个事件可以注册多个监听器。
- 按注册顺序依次执行。
eventTarget.addEventListener(type, lstener[, useCapture]);
eventTarget.addEventListener()
方法将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。
- type:事件类型字符串,比如click、mouseover,注意这里不要带on。
- listener:事件处理函数,事件发生时,会调用该监听函数。
- useCapture:可选参数,是一个布尔值,默认是false。
eventTarget.attachEvent(eventNameWithOn, callback);
eventTarget.attachEvent()
方法将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,指定的回调函数就会被执行。
- eventNameWithOn:事件类型字符串,比如click、mouseover,这里要带on。
- callback:事件处理函数,当目标触发事件时回调函数被调用。
注册事件兼容性解决方案
function addEventListener(element, eventName, fn) {
//判断当前浏览器是否支持addEventListener方法
if (element.addEventListener) {
element.addEventListener(eventName, fn); //第三个参数 默认是false
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, fn);
} else {
//相当于element.onclick = fn;
element['on' + eventName] = fm;
}
}
删除事件
传统注册方式
eventTarget.onclick = null;
方法监听注册方式
eventTarget.removeEventListener(type, listener[, useCapture]);
eventTarget.detachEvent(eventNameWithOn, callback);
删除事件兼容性解决方案
function removeEventListener(element, eventName, fn) {
//判断当前浏览器是否支持removeEventListener方法
if (element.removeEventListener) {
element.removeEventListener(eventName, fn); //第三个参数 默认是false
} else if (element.detachEvent) {
element.detachEvent('on' + eventName, fn);
} else {
element['on' + eventName] = null;
}
}
事件流
事件流描述的是从页面中接收事件的顺序。
DOM事件流:事件发生时会在元素节点之间按照特定的顺序传播。
DOM事件流分为三个阶段:捕获阶段、当前目标阶段和冒泡阶段。
- 事件冒泡:IE最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程。
- 事件捕获:网景最早提出,由DOM最顶层节点开始,然后逐级向下传播到具体的元素接收的过程。
事件流的注意事项
- js代码中只能执行捕获或者冒泡其中的一个阶段。
onclick
和attachEvent
只能得到冒泡阶段。addEventListener(type, listener[, useCapture])
第三个参数如果是true,表示在事件捕获阶段调用事件处理程序;如果是false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序。- 实际开发中很少使用事件捕获,更关注事件冒泡。
- 有些事件是没有冒泡的,比如onblur、onfocus、onmouseenter、onmouseleave。
事件对象
事件对象:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面。它有很多属性和方法。
eventTarget.onclick = function(event) {
//这个event就是事件对象,可以写成e或者evt
}
eventTarget.addEventListener('click', function(event) {
//这个event就是事件对象,可以写成e或者evt
})
- event是个形参,系统帮我们设定为事件对象,不需要传递实参过去。
- 当我们注册事件时,event对象就会被系统自动创建,并以此传递给事件监听器(事件处理函数)。
事件对象的兼容性方案
- 标准浏览器中是浏览器给方法传递的参数,只需要定义形参e就可以获取到。
- 在IE6~8中,浏览器不会给方法传递参数,如果需要的话,需要到window.event中获取查找。
- 解决方案:
e = e || window.event();
。
事件对象的常见属性和方法
事件对象属性方法 | 说明 |
---|---|
e.target | 返回触发事件的对象(标准) |
e.srcElement | 返回触发事件的对象(非标准IE6~8使用) |
e.type | 返回事件的类型,比如click不带on |
e.cancelBubble | 该属性阻止冒泡(非标准IE6~8使用) |
e.returnValue | 该属性阻止默认事件(非标准IE6~8使用),比如不让链接跳转 |
e.preventDefault() | 该方法阻止默认事件(标准),比如不让链接跳转 |
e.stopPropagation() | 阻止冒泡(标准) |
//阻止事件冒泡的兼容性解决方案
if (e && e.stopPropagation) {
e.stopPropagation();
} else {
window.event.cancelBubble = true;
}
事件委托
- 事件委托:不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
e.target.style.backgroundColor = 'pink';
})
其它常见鼠标事件
禁止鼠标右键菜单
contextmenu
主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单。
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
})
禁止鼠标选中
selectstart
开始选中。
document.addEventListener('selectstart', function(e) {
e.preventDefault();
})
鼠标事件对象
鼠标事件对象 | 说明 |
---|---|
e.clientX | 返回鼠标相对于浏览器窗口可视区的X坐标 |
e.clientY | 返回鼠标相对于浏览器窗口可视区的Y坐标 |
e.pageX | 返回鼠标相对于文档页面的X坐标IE9+支持 |
e.pageY | 返回鼠标相对于文档页面的Y坐标IE9+支持 |
e.screenX | 返回鼠标相对于电脑屏幕的X坐标 |
e.screenY | 返回鼠标相对于电脑屏幕的Y坐标 |
e.stopPropagation() | 阻止冒泡(标准) |
常见的键盘事件
键盘事件
键盘事件 | 触发条件 |
---|---|
onkeyup | 某个键盘按键被松开时触发 |
onkeydown | 某个键盘按键被按下时触发 |
onkeypress | 某个键盘按键被按下时触发,但它不识别功能键(比如shift、ctrl) |
- 如果使用addEventListener,不需要添加on。
- 键盘事件的执行顺序:onkeydown -> onkeypress -> onkeyup。
键盘事件对象
键盘事件对象属性 | 说明 |
---|---|
keyCode | 返回该键的ASCII值 |
- onkeydown和onkeyup不区分字母大小写,onkeypress区分字母大小写。
- 更多的使用keydown和keyup,它能识别所有的键(包括功能键)。
BOM
BOM即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其对象是window。
DOM | BOM |
---|---|
文档对象模型 | 浏览器对象模型 |
DOM就是把文档当做一个对象来看待 | 把浏览器当做一个对象来看待 |
DOM的顶级对象是document | BOM的顶级对象是window |
DOM主要是操作页面元素 | BOM主要是浏览器窗口交互的一些对象 |
DOM是W3C标准规范 | BOM是浏览器厂商在各自浏览器上定义的,兼容性较差 |
BOM的构成
- window对象是浏览器的顶级对象,它具有双重角色。
- window对象是js访问浏览器窗口的一个接口。
- window对象是一个全局对象。定义在全局作用域中的变量、函数都会变成window对象的属性和方法。
window对象的常见事件
窗口加载事件
window.onload = function(){}
或者
window.addEventListener("load",function(){});
window.onload
是窗口(页面)加载事件,当文档内容完全加载完成会触发改时间(包括图像、脚本文件、css文件等),就调用的处理函数。
- 有了
window.onload
就可以把js代码写到页面元素的上方,因为onload是等页面内容全部加载完毕,再去执行处理函数。 window.onload
传统注册事件方式只能写一次,如果有多个,会以最后一个window.onload
为准。- 如果使用addEventListener则没有限制。
document.addEventListener('DOMContentLoaded',function(){});
-
DOMContentLoaded事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等。IE9以上才支持。
-
如果页面的图片很多的话,从用户访问到onload触发可能需要较长的时间,交互效果就不能实现,必然影响用户的体验,此时用DOMContentLoaded事件比较合适。
调整窗口大小事件
window.onresize = function(){} window.addEventListener("resize",function(){});
window.onresize
是调整窗口大小加载事件,当触发时就调用的处理函数。
- 只要窗口大小发生像素变化,就会触发这个事件。
- 经常利用这个事件完成响应式布局。
window.innerWidth
当前屏幕的宽度。
定时器
setTimeout()定时器
window.setTimeout(调用函数, [延迟的毫秒数]);
setTimeout()
方法用于设置一个定时器,该定时器在定时器到期后执行调用函数。
- window可以省略。
- 这个调用函数可以直接写函数,或者写函数名或者采取字符串’函数名()'三种形式。第三种不推荐。
- 延迟的毫秒数省略默认是0,如果写,必须是毫秒。
- 因为定时器可能有很多,所以经常给定时器赋值一个标识符。
停止setTimeout()定时器
window.clearTimeout(timeoutID)
clearTimeout()
方法取消了先前通过调用setTimeout()建立的定时器。
- window可以省略。
- 里面的参数就是定时器的标志符。
setInterval()定时器
window.setInterval(回调函数, [间隔的毫秒数]);
setInterval()
方法重复调用一个函数,每隔这个事件,就去调用一次回调函数。
- window可以省略。
- 这个调用函数可以直接写函数,或者写函数名或者采取字符串’函数名()'三种形式。第三种不推荐。
- 间隔的毫秒数省略默认是0,如果写,必须是毫秒,表示每隔多少毫秒就自动调用这个函数。
- 因为定时器可能有很多,所以经常给定时器赋值一个标识符。
停止setInterval()定时器
window.clearInterval(tintervalID)
clearInterval()
方法取消了先前通过调用setInterval()建立的定时器。
- window可以省略。
- 里面的参数就是定时器的标志符。
this
this的指向在函数定义的时候是确定了的,只有函数执行的时候才能确定this到底指向谁,一般情况下this的最终指向的是那个调用它的对象。
- 全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window)。
- 方法调用中谁调用this指向谁。
- 构造函数中this指向构造函数的实例。
js执行队列
js是单线程
-
JavaScaript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。这是因为JavaScript这门脚本语言诞生的使命所致——JavaScript是为处理页面中用户的交互,以及操作DOM而诞生的。比如我们对某个DOM元素进行添加和删除操作,不能同时进行。应该先进行添加,之后再删除。
-
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。这样所导致的问题是:如果js执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
同步和异步
-
同步:前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。
-
异步:你在做一件事情时,因为这件事情会花费很长时间,在做这件事的同时,你还可以去处理其他事情。
-
同步任务都在主线程上执行,形成一个执行栈。
-
js的异步是通过回调函数实现的。一般而言,异步有三种类型:普通事件,资源加载和定时器。异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)。
js执行机制
-
先执行执行栈中的同步任务。
-
异步任务(回调函数)放入任务队列中。
-
一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
-
由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环。
Location对象
- window对象给我们提供了一个location属性用于获取或设置窗体的URL,并且可以用于解析URL。因为这个属性返回的是一个对象,所以我们将这个属性称为location对象。
URL
-
**统一资源定位符(URL)**是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
-
URL的一般语法格式为:protocol://host[:port]/path/[?query]#fragment。
组成 | 说明 |
---|---|
protocol | 通信协议常用的http,ftp,maito等 |
host | 主机(域名) |
port | 端口号 |
path | 路径,由零或多个"/"符号隔开的字符串,一般用来表示主机上的一个目录或文件地址 |
query | 参数,以键值对的形式,通过&符号分割开来 |
fragment | 片段,#后面内容,常见于链接 |
Location对象的属性
location对象属性 | 返回值 |
---|---|
location.href | 获取或者设置整个URL |
location.host | 返回主机(域名) |
location.port | 返回端口号 |
location.pathname | 返回路径 |
location.search | 返回参数 |
location.hash | 返回片段 |
Location对象的方法
location对象方法 | 返回值 |
---|---|
location.assign() | 跟href一样,可以跳转页面(也称为重定向页面) |
location.replace() | 替换当前页面,因为不记录历史,所以不能后退页面 |
location.reload() | 重新加载页面,相当于刷新按钮或者f5 |
navigator对象
navigator.useAgent
返回由客户机发送服务器的user-agent头部的值。
history对象
- window对象给我们提供了一个history对象,与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的URL。
history对象方法 | 作用 |
---|---|
history.back() | 可以后退功能 |
history.forward() | 前进功能 |
history.go(参数) | 前进后退功能,参数如果是1,前进1个页面;如果是-1,后退1个页面 |
PC端网页特效
元素偏移量offset系列
offset属性可以动态的得到该元素的位置(偏移)、大小等。
- 获得元素距离带有定位父元素的位置。
- 获得元素自身的大小(宽度高度)。
- 返回的数值都不带单位。
offset系列属性 | 作用 |
---|---|
element.offsetParent | 返回作为该元素带有定位的父级元素,如果父级都没有定位,则返回body |
element.offsetTop | 返回元素相对带有定位父元素上方的偏移 |
element.offsetLeft | 返回元素相对带有定位元素左边框的偏移 |
element.offsetWidth | 返回自身包括padding、边框、内容区的宽度,返回数值不带单位 |
element.offsetHeight | 返回自身包括padding、边框、内容区的高度,返回数值不带单位 |
offset与style的区别
- offset可以得到任意样式表中的样式值;style只能得到行内样式表中的样式值。
- offset系列获得的数值是没有单位的;style.width获得的是带有单位的字符串。
- offsetWidth包含padding+border+width;style.width获得不包含padding和border的值。
- offsetWidth等属性是只读属性,只能获取不能赋值;style.width是可读写属性,可以获取也可以赋值。
- 获取元素大小位置,用offset更合适 给元素更改值,则需要用style改变。
元素可视区client系列
client属性可以动态的得到该元素的边框大小,元素大小等。
client系列属性 | 作用 |
---|---|
element.clientTop | 返回元素上边框的大小 |
element.clientLeft | 返回元素左边框的大小 |
element.clientWidth | 返回自身包括padding、内容区的宽度,不含边框,返回数值不带单位 |
element.clientHeight | 返回自身包括padding、内容区的高度,不含边框,返回数值不带单位 |
元素滚动scroll系列
scroll属性可以动态的得到该元素的大小、滚动距离等。
scroll系列属性 | 作用 |
---|---|
element.scrollTop | 返回被卷去的上侧距离,返回数值不带单位 |
element.scrollLeft | 返回被卷去的左侧距离,返回数值不带单位 |
element.scrollWidth | 返回自身实际的宽度,不含边框,返回数值不带单位 |
element.scrollHeight | 返回自身实际的的高度,不含边框,返回数值不带单位 |
页面被卷去的头部 兼容性解决方案
- 声明了DTD,使用
document.documentElement.scrollTop
。 - 未声明DTD,使用
document.body.scrollTop
。 - 新方法
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
三大系列总结
- offset系列经常用于获得元素位置(offsetLeft、offsetTop)。
- client系列经常用于获取元素大小(clientWidth、clientHeight)。
- scroll系列经常用于获取滚动距离(scrollTop、scrollLeft)。
- 元素被卷去的头部通过element.scrollTop获得,页面滚动的头部通过window.pageYOffset获得,页面滚动的左侧通过window.pageXOffset获得。
动画函数封装
//轮播图
function animate(obj, tatget, callback) {
//清除之前的定时器
clearInterval(obj.timer);
//设置定时器
obj.timer = setInterval(function{
//缓慢原理
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();
}
}
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
//滚动条
function animate(obj, tatget, callback) {
//清除之前的定时器
clearInterval(obj.timer);
//设置定时器
obj.timer = setInterval(function{
//缓慢原理
var step = (target - window.pageYOffset) / 10;
//将步长值改为整数
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (window.pageYOffset == target) {
//停止动画
clearInterval(obj.timer);
//回调函数写到定时器结束里面
callback && callback()
}
window.scroll(0, window.pageYOffset + step)
}, 15);
}
移动端网页特效
触摸事件
触摸事件 | 作用 |
---|---|
touchstart | 手指触摸DOM元素事件 |
touchumove | 手指在DOM元素身上移动事件 |
touchend | 手指离开DOM元素事件 |
触摸事件对象
-
触摸事件是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多个触电,使开发者可以检测触电的移动,触电的增加和减少,等等。
-
touchstart、touchmove、touchend三个事件都会各自有事件对象。
触摸列表 | 说明 |
---|---|
touches | 正在触摸屏幕的所有手指的一个列表 |
targetTouches | 正在触摸当前DOM元素上的手指的一个列表 |
changeTouches | 手指状态发生了改变的列表,从无到有,从有到无变化 |
classList属性
classList属性是HTML5新增的一个属性,返回元素的类名。但是IE10以上版本支持。该属性用于在元素中添加,移除及切换CSS类。
-
element.classList.add(className);
:添加类。 -
element.classList.remove(className);
:移除类。 -
element.classList.toggle(className);
:切换类。
click延时解决方案
-
移动端click事件会有300ms的延时,原因是移动端屏幕双击会缩放页面。
-
禁用缩放。浏览器禁用默认的双击缩放行为并且去掉300ms的点击延迟。``
-
利用touch事件封装事件解决300ms延迟。
//封装tap,解决click300ms延迟
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) {
//如果手指触摸和离开时间小于150ms算点击
if (!isMove && (Date.now() - startTime) < 150) {
callback && callback(); //执行回调函数
}
isMove = false; //取反 重置
startTime = 0;
});
}
//调用
tap(div, function() {
//执行代码
});
本地存储
本地存储特性
- 数据存储在用户浏览器中。
- 设置、读取方便、甚至页面刷新不丢失数据。
- 容量较大,sessionStorage约5M、localStorage约20M。
- 只能存储字符串,可以将对象JSON.stingfy()编码后存储。
window.sessionStorage
- 生命周期为关闭浏览器窗口。
- 在同一个窗口(页面)下数据可以共享。
- 以键值对的形式存储使用。
sessionStorage.setItem(key,value);
:存储数据。
sessionStorage.getItem(key);
:获取数据。
sessionStorage.removeItem(key);
:删除数据。
sessionStorage.clear();
:删除所有数据。
window.localStorage
- 生命周期永久生效,除非手动删除,否则关闭页面也会存在。
- 可以多窗口(页面)共享(同一浏览器可以共享)。
- 以键值对的形式存储使用。
localStorage.setItem(key,value);
:存储数据。
localStorage.getItem(key);
:获取数据。
localStorage.removeItem(key);
:删除数据。
localStorage.clear();
:删除所有数据。