在上一章,我们说JavaScript这门语言,分为三部分:
- ECMAScript(JavaScript语法)
- DOM(页面文档对象类型)
- BOM(浏览器对象模型)
ECMAScript,JavaScript的语法和基础核心,是所有浏览器厂商共同遵守的一套JavaScript语法工业标准。
DOM,Document Object Model,文档对象模型,通过DOM可以对页面上的各种元素进行操作(大小、位置、颜色等)。
BOM,Browser Object Model,浏览器对象模型,通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等。
上一章,我们主要讨论了"ECMAScript",这一章,我们主要讨论"DOM"和"BOM"。
DOM简介
DOM,Document Object Model,文档对象模型。
是什么文档?
当然是HTML文档。
结构是怎么样的?
我们可以打开一个网页看一下。
最顶端是HTML,然后HTML里面是head和body,body里面还有各种子节点。
就像这样
这就是DOM树。
- 文档:一个页面就是一个文档,DOM中使用
document
表示 - 元素:页面中的所有标签都是元素,DOM中使用
element
表示 - 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用
node
表示
DOM把上述内容都看做是对象
获取元素
如何获取页面元素
那么,我们怎么获取页面元素呢?
什么是元素?页面中的所有标签都是元素。
我们知道,在一个HTML文档中,我们可以为每一个标签设置设置ID,所以可以根据ID获取?
然后每一个标签还有标签名,所以我们还可以根据标签名获取?
然后每一个标签还可能有class属性,所以还可以根据class属性获取?
这几种都对。
获取页面中的元素,有以下几种方式:
- 根据ID获取
- 根据标签名获取
- 通过HTML5新方法获取
- document对象的属性
我们依次来看看。
根据ID获取
getElementById()
,根据ID获取元素对象。
示例代码:
1 | document.getElementById("fullScreen") |
运行结果:
1 | <button id="fullScreen" class="dplayer-icon dplayer-full-icon" data-balloon="全屏" data-balloon-pos="up">…</button> |
获取属性和方法
还可以通过console.dir()
,获取对象的属性和方法。
示例代码:
1 | console.dir(document.getElementById("fullScreen")) |
运行结果:
1 | button#fullScreen.dplayer-icon.dplayer-full-icon |
根据标签名获取
getElementsByTagName()
,根据标签名获取元素的对象集合。
为什么是集合?
因为在HTML中,id不能重复,但是标签名完全可以重复。
示例代码:
1 | document.getElementsByTagName("style") |
运行结果:
1 | HTMLCollection(6) [style, style, style, style, style, style] |
示例代码:
1 | document.getElementsByTagName("kakawanyifan") |
运行结果:
1 | HTMLCollection [] |
特别的,还可以获取某个元素内部所有指定标签名的子元素.
示例代码:
1 | element = document.getElementById("article-container") |
运行结果:
1 | HTMLCollection(3) [style, style, style] |
根据name获取
document.getElementsByName()
,根据"name"获取。
与id不一样,"name"属性的值不要求是唯一的,多个元素可以有同样的名字,如表单中的单选框和复选框。
示例代码:
1 | <html> |
通过HTML5新方法获取
HTML5提供了一些新方法,帮助我们获取元素。
通过类名获取
document.getElementsByClassName()
,通过类名获取元素的集合。
示例代码:
1 | <html> |
通过选择器获取
querySelector()
,返回通过选择器获取到的第一个元素对象。
querySelectorAll()
,返回通过选择器获取到的所有元素对象集合。
注意,querySelector
和querySelectorAll
,根据标签获取元素的时候,不需要加前缀符号;但是根据id和class获取元素的时候,需要加前缀符号。
- id,前缀符号:
#
。 - class,前缀符号:
.
。
document对象的属性
还有一些属性,属于document文档对象的属性,可以直接通过document对象获取。
属性 | 说明 |
---|---|
document.body | 文档的body元素 |
document.title | 文档的title元素 |
document.documentElement | 文档的html元素 |
document.forms | 对文档中所有Form对象引用 |
document.images | 文档中所有Image对象引用 |
示例代码:
1 | console.log(document.images) |
运行结果:
1 | HTMLCollection(22) [img.avatar-img, img.post_bg.ls-is-cached.lazyloaded, img.post_bg.ls-is-cached.lazyloaded, img.post_bg.ls-is-cached.lazyloaded, img.post_bg.ls-is-cached.lazyloaded, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.post_bg.lazyload, img.avatar-img] |
操作元素
通过上文的讨论,我们已经知道了如何获取元素。
接下来,我们讨论如何操作元素。
操作元素内容
三种方法
属性 | 说明 |
---|---|
element.innerHTML |
元素开始和结束标签之间的HTML,包括HTML标签,同时保留空格和换行 |
element.innerText |
元素的文本内容,在返回的时候会去除HTML标签和多余的空格、换行,在设置的时候会进行特殊字符转义 |
element.textContent |
节点的文本内容,同时保留空格和换行 |
接下来通过案例进行演示。
分别利用innerHTML、innerText、textContent属性在控制台输出一段HTML文本,示例代码如下。
示例代码:
1 | <html> |
1 | var oBox = document.getElementById('box') |
运行结果:
1 | '\n The first paragraph...\n <p>\n The second paragraph...\n <a href="http://www.example.com">third</a>\n </p>\n ' |
兼容性问题
innerText
是非标准的方法,存在兼容性问题。
innerHTML
是标准方法,不存在兼容性问题。
建议:innerHTML
。
操作元素属性
在上文我们讨论过,DOM把每一个节点(元素)都看做对象。
我们怎么访问对象的属性?
对象.属性
即可。
示例代码:
1 | var imgDemo = document.getElementById('imgDemo') |
操作元素样式
怎么操作元素的样式?
元素的样式由两个属性控制,style属性和className属性。
所以,操作元素样式有两种方法:
- 操作style属性
- 操作className属性
我们分别讨论。
操作style属性
元素对象.style.样式属性名
样式属性名对应CSS样式名,但需要去掉CSS样式名中的-
,并将-
后面的英文的首字母大写。
例如,设置字体大小的样式名font-size,对应的样式属性名为fontSize。
常见的style属性操作的样式名如下。
名称 | 说明 |
---|---|
background |
元素的背景属性 |
backgroundColor |
元素的背景色 |
display |
元素的显示类型 |
fontSize |
元素的字体大小 |
width |
元素的宽度 |
height |
元素的高度 |
overflow |
如何处理呈现在元素框外面的内容 |
textAlign |
文本的水平对齐方式 |
示例代码:
1 | // 获取元素对象 |
操作className属性
如果样式修改较多,可以采取操作类名的方式更改元素样式,语法为元素对象.className
。
示例代码:
1 | <html> |
1 | var t = document.querySelector('div')[0]; |
属性操作
上文不是已经讨论过了属性操作吗?
为什么这里再讨论?
因为通过element.属性
的方式来获取属性值的方法,只对内置的属性值有效。
对于我们自定义的属性的值,需要利用getAttribute('属性')
获取指定元素的属性值。
当然,getAttribute('属性')
,对于内置属性同样有效。
获取属性
getAttribute
id
可以直接用.属性
的方法获取,但是index
,无法直接用.属性
的方法获取。
示例代码:
1 | <html> |
运行结果:
1 | demo |
element.dataset.属性
除了上述方法,还可以通过element.dataset.属性
、element.dataset['属性']
的方式获取。
示例代码:
1 | <html> |
运行结果:
1 | 2 |
解释说明:
- 该方法只能获取"data-"开头的属性
- 如果自定义属性里面包含有多个连字符
-
时,获取的时候采取驼峰命名法 - 该方法存在兼容性问题
设置属性
element.setAttribute('属性', '值')
,设置属性。
示例代码:
1 | <html> |
与获取属性类似,对于前缀为data-
的属性,还可以通过元素对象.dataset.属性名='值'
、元素对象.dataset[属性名]='值'
设置属性。
移除属性
在DOM中使用element.removeAttribute('属性')
的方式来移除元素属性。
示例代码:
1 | <html> |
节点操作
节点属性
一个节点,至少拥有三个属性:
nodeType
:节点类型1
:元素节点2
:属性节点3
:文本节点
nodeName
:节点名称nodeValue
:节点值
节点层级
节点层级关系
假设存在一份HTML文档如下:
示例代码:
1 |
|
- 根节点:
<html>
标签是整个文档的根节点,有且仅有一个。 - 父节点:某一个节点的上级节点,例如,
<html>
是<head>
和<body>
的父节点。 - 子节点:某一个节点的下级节点,例如,
<head>
和<body>
节点是<html>
节点的子节点。 - 兄弟节点:两个节点同属于一个父节点,例如,
<head>
和<body>
互为兄弟节点。
获取父节点
parentNode
属性来获得离当前元素的最近的一个父节点,如果找不到父节点就返回null
,语法格式为:obj.parentNode
。
示例代码:
1 | <html> |
1 | var child = document.querySelector('.child'); |
运行结果:
1 | <span class="child">span元素</span> |
获取子节点
获取子节点有两种方法,childNodes
和children
。
我们分别讨论。
childNodes
示例代码:
1 | <html> |
1 | var ul = document.querySelector('ul'); |
运行结果:
1 | console.log(ul.childNodes[1].nodeType); |
解释说明:childNodes返回子元素节点和子文本节点。
children
示例代码:
1 | <html> |
1 | var ul = document.querySelector('ul'); |
运行结果:
1 | console.log(ul.children[1].nodeType); |
解释说明:children只返回子元素节点,其余节点不返回。
比较
- 返回节点
childrenNodes
返回子元素节点和子文本节点。
children
只返回子元素节点,其余节点不返回。 - 兼容性
childrenNodes
存在兼容性问题,而且在某些浏览器下不返回子文本节点。
children
不存在兼容性问题。
获取第一个子节点和最后一个子节点
firstChild
和lastChild
,可以获取第一个子节点和最后一个子节点。
firstElementChild
和lastElementChild
,获取第一个子元素节点和最后一个子元素节点。
示例代码:
1 | <html> |
1 | var ul = document.querySelector('ul'); |
运行结果:
1 | #text |
但是,firstElementChild
和lastElementChild
,可能存在兼容性问题,在IE9以上才支持。
虽然该兼容问题可以忽略不计,谁会去兼容IE9以下的的浏览器呢?
如果确实需要兼容,可以考虑这么做
1 | // 获取第一个子元素节点 |
获取兄弟节点
nextSibling
获取下一个兄弟节点,previousSibling
获取上一个兄弟节点。其返回值包含元素节点或者文本节点等。
nextElementSibling
获取下一个兄弟元素节点,previousElementSibling
获取上一个兄弟元素节点。但是可能存在兼容性问题,在IE9以上才支持。
虽然该兼容问题可以忽略不计,谁会去兼容IE9以下的的浏览器呢?
如果确实要兼容,可以考虑这么做
1 | function getNextElementSibling(element) { |
创建节点
document.write()
document.write()
如果页面文档流加载完毕,再调用会导致页面重绘。
element.innerHTML
element.innerHTML
将内容写入某个DOM节点,不会导致页面全部重绘。
document.createElement()
document.createElement()
效率稍微低一点,但是结构更加清晰。
添加和删除节点
appendChild()
appendChild()
,将一个节点添加到指定父节点的子节点列表末尾。
insertBefore()
insertBefore(child, 指定元素)
,将一个节点添加到父节点的指定子节点前面。
removeChild(child)
removeChild(child)
,移除子节点。
复制节点
node.cloneNode()
,返回调用该方法的节点的一个副本。如果括号参数为true,则是深拷贝,即会复制节点本身及里面所有的子节点。
示例代码:
1 | <html> |
运行结果:
事件三要素
事件由事件源、事件类型和事件处理程序组成,称为事件三要素。
- 事件源:触发事件的元素。
谁触发了事件 - 事件类型:如click单击事件。
触发了什么事件 - 事件处理程序:事件触发后要执行的代码(函数形式),也称事件处理函数。
触发事件以后要做什么
事件触发
注册事件
注册事件有两种方式,传统方式和事件监听方式。
传统方式
示例代码:
1 | <html> |
事件监听方式
事件监听方式又有两种。
- attachEvent
- addEventListener
attachEvent
DOM对象.attachEvent(type, callback);
type
指的是为DOM对象绑定的事件类型,它是由on与事件名称组成的,如onclick。callback
表示事件的处理程序。
这种方法主要存在于IE9之前的浏览器。
addEventListener
DOM对象.addEventListener(type, callback, [capture]);
type
指的是DOM对象绑定的事件类型,它是由事件名称设置的,如click。callback
表示事件的处理程序。capture
默认值为false,表示在冒泡阶段完成事件处理,将其设置为true时,表示在捕获阶段完成事件处理。
(关于capture
,我们在下文讨论事件流的时候看具体区别。)
示例代码:
1 | <html> |
事件流
在浏览器发展历史中,网景(Netscape)的事件流采用事件捕获方式,指的是事件流传播的顺序应该是从DOM树的最上层开始出发一直到发生事件的元素节点;微软(Microsoft)的事件流采用事件冒泡方式,指的是事件流传播的顺序应该是从发生事件的元素节点到DOM树的根节点。
示例代码:
1 | <html> |
运行结果:
1 | btn |
解释说明:默认是冒泡。
示例代码:
1 | <html> |
运行结果:
1 | body |
解释说明:设置为true之后,是事件捕获。
删除事件
对应三种注册事件的方式,有三种删除事件的方式。
DOM对象.onclick = null;
DOM对象.detachEvent(type, callback);
DOM对象.removeEventListener(type, callback);
事件对象
什么是事件对象
事件对象是事件一系列相关数据的集合。
例如,鼠标单击的事件对象,包含了鼠标指针坐标等。键盘事件,包含了被按下的键值代码等。
获取事件对象
一般通过DOM对象.事件 = function (event) {}
就可以获取事件对象。
但是在IE9之前的浏览器中,只能通过window.event
才能获取事件对象,var 事件对象 = window.event
。
如果一定要兼容IE9之前的浏览器的话,可以采取这种方法。
1 | btn.onclick = function(e) { |
事件对象的属性和方法
常见的事件对象的属性和方法
属性/方法 | 说明 | 浏览器 |
---|---|---|
e.target |
触发事件的对象 | 标准浏览器 |
e.srcElement |
触发事件的对象 | IE9之前 |
e.type |
事件的类型 | 所有浏览器 |
e.stopPropagation() |
阻止事件冒泡 | 标准浏览器 |
e.cancelBubble() |
阻止事件冒泡 | IE9之前 |
e.preventDefault() |
阻止默认事件(例如,链接跳转) | 标准浏览器 |
e.returnValue() |
阻止默认事件(例如,链接跳转) | IE9之前 |
我们解释一下,什么是事件冒泡。
当一个事件发生在一个元素上,它会首先运行在该元素上的处理程序,然后运行其父元素上的处理程序,然后一直向上到其他祖先上的处理程序。
不阻止冒泡。
示例代码:
1 | <html> |
运行结果:
1 | btn |
解释说明:事件冒泡。
示例代码:
1 | <html> |
运行结果:
1 | btn |
解释说明:阻止事件冒泡。
事件委托
事件委托:不给子元素注册事件,给父元素注册事件,让处理代码在父元素的事件中执行。
示例代码:
1 | <html> |
解释说明:首先获取到ul父元素,并且给父元素绑定单击事件,进而实现单击子元素li时,给当前项改变背景色。
鼠标事件
常见的鼠标事件
事件名称 | 事件触发机制 |
---|---|
click |
单击鼠标左键时触发 |
focus |
获得鼠标指针焦点触发 |
blur |
失去鼠标指针焦点触发 |
mouseover |
鼠标指针经过时触发 |
mouseout |
鼠标指针离开时触发 |
mousedown |
当按下任意鼠标按键时触发 |
mouseup |
当释放任意鼠标按键时触发 |
mousemove |
在元素内当鼠标指针移动时持续触发 |
contextmenu |
鼠标右击 |
selectstart |
鼠标选中 |
鼠标事件对象的属性
属性 | 描述 |
---|---|
clientX |
鼠标指针位于浏览器页面当前窗口可视区的水平坐标(X轴坐标) |
clientY |
鼠标指针位于浏览器页面当前窗口可视区的垂直坐标(Y轴坐标) |
pageX |
鼠标指针位于文档的水平坐标(X轴坐标),IE9以下不兼容 |
pageY |
鼠标指针位于文档的垂直坐标(Y轴坐标),IE9以下不兼容 |
screenX |
鼠标指针位于屏幕的水平坐标(X轴坐标) |
screenY |
鼠标指针位于屏幕的垂直坐标(Y轴坐标) |
IE9以下不兼容pageX和pageY属性。
如果一定要去兼容的话,可以考虑这种方式:
1 | var pageX = event.pageX || event.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft); |
键盘事件
常见的键盘事件
事件名称 | 事件触发机制 |
---|---|
keypress |
某个键盘按键被按下时触发。不识别功能键,如Ctrl 、Shift 、箭头 等 |
keydown |
某个键盘按键被按下时触发 |
keyup |
某个键盘按键被松开时触发 |
键盘事件对象的属性
常用的键盘事件对象的属性,只有一个,keyCode
,被按下的键的值。
例如:
按键 | keyCode |
---|---|
Enter |
13 |
Left Arrow |
37 |
Up Arrow |
38 |
Right Arrow |
39 |
Down Arrow |
40 |
键盘映射表
字母和数字键的键码值(keyCode)按键 | 键码 | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 |
---|---|---|---|---|---|---|---|
A | 65 | J | 74 | S | 83 | 1 | 49 |
B | 66 | K | 75 | T | 84 | 2 | 50 |
C | 67 | L | 76 | U | 85 | 3 | 51 |
D | 68 | M | 77 | V | 86 | 4 | 52 |
E | 69 | N | 78 | W | 87 | 5 | 53 |
F | 70 | O | 79 | X | 88 | 6 | 54 |
G | 71 | P | 80 | Y | 89 | 7 | 55 |
H | 72 | Q | 81 | Z | 90 | 8 | 56 |
I | 73 | R | 82 | 0 | 48 | 9 | 57 |
按键 | 键码 | 按键 | 键码 |
---|---|---|---|
0 | 96 | 8 | 104 |
1 | 97 | 9 | 105 |
2 | 98 | * | 106 |
3 | 99 | + | 107 |
4 | 100 | Enter | 108 |
5 | 101 | – | 109 |
6 | 102 | . | 110 |
7 | 103 | / | 111 |
按键 | 键码 | 按键 | 键码 |
---|---|---|---|
F1 | 112 | F7 | 118 |
F2 | 113 | F8 | 119 |
F3 | 114 | F9 | 120 |
F4 | 115 | F10 | 121 |
F5 | 116 | F11 | 122 |
F6 | 117 | F12 | 123 |
按键 | 键码 | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 |
---|---|---|---|---|---|---|---|
BackSpace | 8 | Esc | 27 | Right Arrow | 39 | -_ | 189 |
Tab | 9 | Spacebar | 32 | Dw Arrow | 40 | .> | 190 |
Clear | 12 | Page Up | 33 | Insert | 45 | /? | 191 |
Enter | 13 | Page Down | 34 | Delete | 46 | `~ | 192 |
Shift | 16 | End | 35 | Num Lock | 144 | [{ | 219 |
Control | 17 | Home | 36 | ;: | 186 | \ | 220 |
Alt | 18 | Left Arrow | 37 | =+ | 187 | ]} | 221 |
Cape Lock | 20 | Up Arrow | 38 | ,< | 188 | ‘“ | 222 |
触屏事件
常见的触屏事件
事件名称 | 事件触发机制 |
---|---|
touchstart |
手指触摸到一个元素时触发 |
touchmove |
手指在一个元素上滑动时触发 |
touchend |
手指从一个元素上移开时触发 |
触屏事件对象的属性
事件名称 | 事件触发机制 |
---|---|
touches |
正在触屏的所有手指的列表 |
targetTouches |
正在触摸当前元素的手指的列表 |
changedTouches |
手指状态发生了改变的列表 |
元素位置和滚动
offset概述
offset的含义是偏移量,使用offset的相关属性可以动态地获取该元素的位置、大小等。
属性 | 说明 |
---|---|
offsetLeft |
返回元素相对其带有定位的父元素左边框的偏移 |
offsetTop |
返回元素相对其带有定位的父元素上方的偏移 |
offsetWidth |
返回自身的宽度(包括padding、边框和内容区域的宽度),不带单位 |
offsetHeight |
返回自身的高度(包括padding、边框和内容区域的高度),不带单位 |
offsetParent |
返回作为该元素带有定位元素的父级元素(如果父级都没有定位则返回body) |
offset与style的区别
offset系列和style属性都可以获得元素样式的属性和位置,那么两者有什么区别呢?
- 作用范围
offset可以得到任意样式表中的样式值
style只能得到行内样式表中的样式值 - 单位
offset系列获得的数值是没有单位的
style.width获得的是带有单位的字符串 - 度量标准
offsetWidth包含padding、border、width的值
style.width获得的是不包含padding、border的值 - 读写属性
offsetWidth等属性是只读属性,只能获取不能赋值
style.width是可读写属性,可以获取也可以赋值
元素可视区
使用client系列的相关属性可以获取元素可视区的相关信息。例如,可以动态地得到元素的边框大小、元素大小等。
属性 | 说明 |
---|---|
clientLeft |
返回元素左边框的大小 |
clientTop |
返回元素上边框的大小 |
clientWidth |
返回自身的宽度(包含padding),内容区域的宽度(不含边框)。注意返回数值不带单位 |
clientHeight |
返回自身的高度(包含padding),内容区域的高度(不含边框)。注意返回数值不带单位 |
示例代码:
1 | <html> |
运行结果:
元素滚动
scroll的含义是滚动,使用scroll系列的相关属性可以动态地获取该元素的滚动距离、大小等。
属性 | 说明 |
---|---|
scrollLeft |
返回被卷去的左侧距离,返回数值不带单位 |
scrollTop |
返回被卷去的上方距离,返回数值不带单位 |
scrollWidth |
返回自身的宽度,不含边框。注意返回数值不带单位 |
scrollHeight |
返回自身的高度,不含边框。注意返回数值不带单位 |
示例代码:
1 | <html> |
运行结果:
BOM简介
BOM,Brower Object Model,浏览器对象模型,提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是window。
BOM提供了很多的对象。这些对象用于访问浏览器,被称为浏览器对象。
如图所示。
- BOM比DOM更大,它包含DOM(document)。
- BOM的核心对象是window,其他的对象称为window的子对象
- 定义在全局作用域中的变量、函数都会变成window对象的属性和方法。
示例代码:
1 | var num = 10; |
运行结果:
1 | 10 |
window对象的常见事件
window.onload
window.onload
是窗口(页面)加载事件,当文档内容(包括图像、脚本文件、CSS文件等)完全加载完成会触发该事件,调用该事件对应的事件处理函数。
因为JavaScript代码是从上往下依次执行的,如果要在页面加载完成后执行某些代码,又想要把这些代码写到页面任意的地方,可以把代码写到window.onload事件处理函数中。
onload页面加载事件有两种注册方式,分别如下。
window.onload = function () {};
window.addEventListener('load', function () {});
之间的区别为:window.onload
注册事件的只能写一次,如果有多个,会以最后一个window.onload
为准;addEventListener
没有限制。
window.onbeforeunload
window.onbeforeunload
,当窗口即将被卸载(关闭)时,会触发该事件,此时页面文档依然可见,且该事件的默认动作可以被取消。
window.onunload
window.onunload
,该事件在关闭窗口资源和内容的时候触发。
定时器
方法 | 说明 |
---|---|
setTimeout() |
在指定的毫秒数后调用函数或执行一段代码 |
setInterval() |
按照指定的周期(以毫秒计)来调用函数或执行一段代码 |
clearTimeout() |
取消由setTimeout()方法设置的定时器 |
clearInterval() |
取消由setInterval()设置的定时器 |
格式如下:
1 | setTimeout(调用的函数, [延迟的毫秒数]) |
1 | setInterval(调用的函数, [延迟的毫秒数]) |
调用的函数可以是一段代码、一个函数或者一个函数名。
示例代码:
1 | // 参数形式1:用字符串表示一段代码 |
注意:
- 当参数为一个函数名时,这个函数名不需要加()小括号,否则就变成了立即执行这个函数,将函数执行后的返回值传入。
- 延迟的毫秒数,默认为0。
在实际开发中,一个网页中可能会有很多个定时器,所以建议用一个变量保存定时器的id(唯一标识)。若想要在定时器启动后,取消该定时器操作。
示例代码:
1 | // 在设置定时器时,保存定时器的唯一标识 |
在《基于Java的后端开发入门:99.iPhone设备的一个BUG》中,最后的解决方案,利用的就是定时任务。
1 | let highlightSize = $('.highlight').length |
观察者
观察者,Observer,在JavaScript中一共有4种观察者。
- Intersection Observer
- Mutation Observer
- Resize Observer
- Performance Observer
Intersection Observer
功能
有时候,我们需要监测某个元素是否出现可视范围内,例如:
- 懒加载,当出现在可视范围内才进行加载。
- 无限滚动(Infinite Scroll),当页面滚动到底部的时候,自动载入更多内容
- 计算广告在页面的曝光次数。
在以往,我们需要绑定scroll事件,然后不断的计算当前scroll的坐标,进行相关的逻辑处理。
这个太麻烦了,而且性能不会太好。
我们可以把这些工作交给IntersectionObserver。
角色
在Intersection Observer中有两个角色:
root
外层的容器,target
的ancestor元素(父元素,父元素的父元素,祖先元素)。target
会在root
容器内出现的元素
例如,在下文的例子中,随着滚动条的滚动,target
在root
的可视范围不断变化,target
上的数字表示的是可见程度。
See the Pen Intersection Observer Demo by KakaWanYifan (@KakaWanYifan) on CodePen.
当滚动条滚到target
刚好出现在root
可视范围或是完整离开可视范围的那一瞬间,可见程度是0;当target
完整的出现在root
的可视范围内,可见程度是1。
特别的,如果target
的高度是root
可视范围的两倍呢?那么最多可以看到半个target
,即可见程度最高只会有0.5。
实例化
1 | const options = { |
callback
,回调函数options
,可选参数root
:不指定或为空,代表浏览器的可视范围。rootMargin
:用來修改root元素的观察范围。threshold
:可見程度,可以是浮点数或者数组,例如[0, 0.25, 0.5, 0.75, 1]
,当满足可见程度时,调用callback
(回调函数)。
观察target
上文,我们只是定义了一个观察者,现在我们要用这个观察者来观察target。示例代码:
1 | const target = document.querySelector('#listItem'); |
callback函数
1 | const callback = (entries, observer) => { |
callback函数接受两个参数:
entries
:IntersectionObserverEntry
的数组
IntersectionObserverEntry
的属性很多,我们会用到的有isIntersecting
:target是否可见,即使只有1px也算可见intersectionRatio
:target可见比例
observer
:观察者本身(即是哪一位观察者触发了callback)
例子
1 | const root = document.querySelector('#root'); |
Mutation Observer
功能
监听某个元素在某个时候发生了哪些具体的变化。
使用
有了Intersection Observer
的基础,其实Mutation Observer
很简单了。
1 | // 选择需要观察变动的节点 |
config
中的属性有:
attributes
,是否观察,属性的变动。childList
,是否观察,子节点的变动(指新增,删除或者更改)characterData
,是否观察,节点内容或节点文本的变动。subtree
,是否将该观察器应用于该节点的所有子节点。attributeOldValue
,观察attributes
变动时,是否需要记录变动前的属性值。characterDataOldValue
,观察characterData变动时,是否需要记录变动前的值。attributeFilter
,一个数组,观察的特定属性,例如['class','src']
Resize Observer
使用
监听元素的尺寸变化。
使用方法很简单,没有太多的属性配置,示例代码:
1 | var observer = new ResizeObserver(callback); |
例子
1 | <div id="target"></div> |
注意
- 对于不可替换内联元素不触发
不可替换内联元素是指其内容不会被替换或继承,相对于其父元素的文本流位置是不可变的。例如,span元素就是一个不可替换的内联元素。 - CSS transform 操作不触发
- 元素被插入或移除时会触发,元素display从显示变成none或相反过程时会触发
Performance Observer
Performance Observer,用来监控各种性能相关的指标,本文不讨论。
localtion对象
URL的组成
location对象与url相关,在讨论location对象前,我们先讨论一下url的组成。
在一个url中,包含了网络协议、服务器的主机名、端口号、资源名称字符串、参数以及锚点,具体:
1 | protocol://host[:port]/path/[?query]#fragment |
各部分 | 说明 |
---|---|
protocol | 网络协议,常用的如http,ftp,mailto等 |
host | 服务器的主机名,如www.example.com |
port | 端口号,可选,省略时使用协议的默认端口,如http默认端口为80 |
path | 路径,如/web/index.html |
query | 参数,键值对的形式,通过& 符号分隔,如a=3&b=4 |
fragment | 锚点,如#res ,表示页面内部的锚点 |
location常用属性
属性 | 说明 |
---|---|
location.search |
当前URL的查询部分(? 之后的部分) |
location.hash |
锚部分(从# 开始的部分) |
location.host |
主机名和端口 |
location.hostname |
主机名 |
location.port |
端口 |
location.href |
完整的URL |
location.pathname |
路径名 |
location.protocol |
协议 |
location常用方法
location对象提供的用于改变URL地址的方法。
方法 | 作用 |
---|---|
reload() |
重新加载当前文档 |
replace() |
用新的文档替换当前文档,覆盖浏览器当前记录 |
reload()
,从服务器上重新下载该文档,类似于"刷新页面"。
replace()
,使浏览器位置改变,并且禁止在浏览器历史记录中生成新的记录。
那么,我们如何在前端页面实现重定向呢?
除了replace()
,还有location.href
等,这几种方法存在区别
具体可以参考我们在《基于Hexo的博客搭建:8.重定向》中的讨论。
navigator对象
navigator对象包含有关浏览器的信息,每个浏览器中的navigator对象中都有一套自己的属性。
常见的navigator对象的属性如下:
属性 | 说明 |
---|---|
appCodeName |
浏览器的内部名称 |
appName |
浏览器的完整名称 |
appVersion |
浏览器的平台和版本信息 |
cookieEnabled |
浏览器中是否启用Cookie的布尔值 |
platform |
运行浏览器的操作系统平台 |
userAgent |
客户端发送到服务器的User-Agent头部的值 |
history对象
history
,历史记录。
出于安全方面的考虑,history
对象不能直接获取用户浏览过的URL,只能实现"后退"和"前进"的功能。
方法 | 作用 |
---|---|
back() |
加载history列表中的前一个URL |
forward() |
加载history列表中的下一个URL |
本地存储
最后一个话题,本地存储。
本地存储方法有两种:
- cookie
- storage
我们分别讨论。
cookie
写cookies
示例代码:
1 | function setCookie(name,value){ |
如果不设置expires
,在浏览器关闭时就会删除cookie。
读取cookies
示例代码:
1 | function getCookie(name){ |
删除cookies
示例代码:
1 | function delCookie(name){ |
解释说明:让cookie立即超时,失效。
storage
相比cookie
,更推荐用storage
来做本地存储。
storage
分为两种,sessionStorage
和localStorage
,我们分别讨论。
sessionStorage
sessionStorage
,特点有:
- 生命周期为关闭浏览器窗口
- 在同一个窗口(页面)下数据可以共享
- 以键值对的形式存储使用
存储数据:
1 | sessionStorage.setItem(key, value) |
获取数据:
1 | sessionStorage.getItem(key) |
删除数据:
1 | sessionStorage.removeItem(key) |
删除所有数据:
1 | sessionStorage.clear() |
localStorage
localStorage
,特点有:
- 永久有效,即使关闭页面也会存在。除非手动删除
- 可以多窗口(页面)共享,即同一浏览器可以共享
- 以键值对的形式存储使用
存储数据:
1 | localStorage.setItem(key, value) |
获取数据:
1 | localStorage.getItem(key) |
删除数据:
1 | localStorage.removeItem(key) |
删除所有数据:
1 | localStorage.clear() |
比较
相同点
cookie
,sessionStorage
,localStorage
都是在客户端保存数据的,并且都是key-value类型。
不同点
生命周期
cookie
如果不设置有效期,那么就是临时存储,浏览器关闭,cookie
也就失效了。如果设置了有效期,那么有效期到了,就自动消失了。
sessionStorage
仅在当前会话下有效。
localStorage
的生命周期是永久的,关闭页面或浏览器之后localStorage
中的数据也不会消失。除非主动删除数据,否则数据永远不会消失。
大小限制
cookie
大小限制在4KB
localstorage
和sessionStorage
的大小限制为5M。
安全性
localstorage
和sessionStorage
不会随着HTTP header发送到服务器端,安全性相对于cookie
来说比较高一些。
便捷性
localstorage
和sessionStorage
相关的一些操作数据的方法的确比cookie
便捷很多。