DOM
DOM(文档对象模型)是指浏览器将HTML文档解析成一颗树状结构,通过该结构可以操作文档中的元素和内容
nodeType
节点的 nodeType
属性可以显示这个节点具体的类型
nodeType值 | 节点类型 |
---|---|
1 | 元素节点,例如p div |
3 | 文字节点 |
8 | 注释节点 |
9 | document节点 |
10 | DTD节点 |
节点访问
getElementById()
注意
通过 ID
获取元素的上下文只能是 document
,getElementById
只在 Document
类的原型上,HTMLDivElement
没有继承 Document
类,所以div
不能使用 getElementById
方法
document.getElementById()
功能是通过id得到元素节点
- 如果页面上有相同
id
的元素,则只能得到第一个(一个页面一个id
命名一般只能出现一次) - 括号里面不要写
#
不常用
getElementsByTagName()getElementsByTagName()
方法的功能是通过标签名得到节点数组
- 数组方便遍历,从而可以批量操控元素节点
- 即使页面上只有一个指定标签名的节点,也将得到长度为 1 的数组
- 上下文可以是
document
,也可以是一个元素
getElementsByClassName()
getElementsByClassName()
方法的功能是通过类名得到节点数组
- 即使页面上只有一个指定类名的节点,也将得到长度为 1 的数组
- 括号内不要写"."
- 上下文可以是
document
,也可以是一个元素
querySelector()
querySelector()
方法的功能是通过选择器得到元素
querySelector()
方法只能得到页面上一个元素,如果有多个元素符合条件,则只能得到第一个元素上下文可以是
document
,也可以是一个元素
querySelectorAll()
querySelectorAll()
方法的功能是通过选择器得到元素数组
即使页面上只有一个符合选择器的节点,也将得到长度为 1 的数组
上下文可以是
document
,也可以是一个元素
节点关系
注意
DOM
中,文本节点也属于节点,在使用节点的关系时一定要注意在标准的
W3C
规范中,空白文本节点也应该算作节点,但是在IE8
及以前的浏览器中会有一定的兼容问题,它们不把空文本节点当做节点
关系 | 考虑所有节点 | 只考虑元素节点 |
---|---|---|
子节点 | childNodes | children |
父节点 | parentNode | 同 |
第一个子节点 | firstChild | firstElementChild |
最后一个子节点 | lastChild | lastElementChild |
前一个兄弟节点 | previousSibling | previousElementSibling |
后一个兄弟节点 | nextSibling | nextElementSibling |
节点操作
改变内容
改变元素节点中的内容可以使用两个相关属性
- innerHTML 属性能以
HTML
语法设置节点中的内容 - innerText 属性只能以纯文本的形式设置节点中的内容
改变样式
box.style.backgroudColor = 'red'
改变属性
标准 W3C
属性,如 src
、href
等等,只需要直接打点进行更改即可
oImg.src = 'images/2.png'
class
属性需要通过 className
属性 获取和修改,而不是class
,修改该值将直接覆盖之前所有的类名
classList
属性返回元素的类名,该属性用于在元素中添加,移除及切换 CSS 类,classList
属性是只读的,但你可以使用 add() 和 remove() 方法修改它:
document.getElementById('myDIV').classList.add('mystyle')
不符合 W3C
标准的属性,要使用 setAttribute()
和 getAttribute()
来设置、读取
oBox.setAttribute('number', 10)
var n = oBox.getAttribute('number')
alert(n) //10
自定义属性
在 HTML5 中添加了 data-
的方式来自定义属性,所谓 data-
实际上就是 data-
前缀加上自定义的属性名,使用这样的结构可以进行数据存放。使用 data-
可以解决自定义属性混乱无管理 的现状
- 设置自定义属性的 2 种方式:
(1)第一种方式是可以直接在 HTML
标签上面书写:
<h2 data-weather="rain">今天下雨啦</h2>
上面 data-weather
就是一个自定义属性,值为 rain
注意:如果设置的自定义属性是多个单词的组合的话,需要用中横线(-)链接,比如:
<h2 data-birth-date="20201128">今天下雨啦</h2>
(2)第二种方式是通过 js
的 dataset
属性来设置:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<h2>今天下雨啦</h2>
<script>
var h2 = document.querySelector('h2')
h2.dataset.weather = 'rain'
</script>
</body>
</html>
这样也是设置了一个 data-weater
的自定义属性,值为 rain
,HTML5
中元素都会有一个 dataset
的属性
注意:如果设置的是多个单词的组合的话,需要使用驼峰命名法来书写,如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<h2>今天下雨啦</h2>
<script>
var h2 = document.querySelector('h2')
h2.dataset.birthDate = '20201128'
</script>
</body>
</html>
- js 读取自定义属性
读取的时候通过 dataset
属性来获取自定义属性,需要去掉 data-
前缀,连字符需要转化为驼峰命名,如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<h2 data-weather="rain" data-birth-date="20201128">今天下雨啦</h2>
<script>
var h2 = document.querySelector('h2')
console.log(h2.dataset.weather) // rain
console.log(h2.dataset.birthDate) // 20201128
</script>
</body>
</html>
CSS
也可以通过自定义属性来书写样式,如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<style>
h2[data-birth-date='20201128'] {
color: red;
}
</style>
</head>
<body>
<h2 data-birth-date="20201128">今天下雨啦</h2>
</body>
</html>
- 自定义属性
demo
当然也可以使用 setAttribute()和 getAttribute()来设置、读取
创建节点
document.createElement()
方法用于创建一个指定 tagName
的 HTML
元素
var oDiv = document.createElement('div')
新创建出的节点并没有被挂载到 DOM
树上,必须继续使用 appendChild()
或insertBefore()
方法将新创建的节点插入到 DOM 树上
document.createDocumentFragment()
用于创建文档片段,将元素附加到文档片段,然后将文档片段附加到 DOM
树。在DOM
树中,文档片段被其所有的子元素所代替。
因为文档片段存在于内存中,并不在DOM
树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段通常会带来更好的性能。
const list = document.querySelector('.list')
// 文档切片
const frag = document.createDocumentFragment()
for (let i = 0; i < 10000; i++) {
const title = document.createElement('h1')
title.innerText = `list item ${i}`
frag.appendChild(title)
}
list.appendChild(frag)
appendChild()
任何已经在DOM
树上的节点,都可以调用 appendChild()
,它可以将新节点挂载到它的内部,成为它的最后一个节点
父节点.appendChild(新节点)
insertBefore()
任何已经在 DOM
树上的节点,都可以调用insertBefore()
方法,它可以将孤儿节点挂载到它的内部,成为它的某个子节点之前的节点
父节点.insertBefore(新节点, 父节点的某个子节点)
移动节点
如果将已经挂载到 DOM
树上的节点成为 appendChild()
或者 insertBefore()
的参数,这个节点将会被移动
新父节点.appendChild(已经有父亲的节点)
新父节点.insertBefore(已经有父亲的节点, 新父节点的某个子节点)
删除节点
removeChild()
方法从DOM
中删除一个子节点- 节点不能主动删除自己,必须由父节点删除它
克隆节点
cloneNode()
方法可以克隆节点
var newNode = 老节点.cloneNode()
var newNode = 老节点.cloneNode(true)
- 参数是一个布尔值,表示是否采用深度克隆:如果为 true,则该节点的所有后代节点也都会被克隆,如果为 false,则只克隆该节点本身
DOM 事件
事件监听
常见的鼠标事件监听
事件名 | 事件描述 |
---|---|
onclick | 当鼠标单击某个对象 |
ondbclick | 当鼠标双击某个对象 |
onmousedown | 当某个鼠标按键在某个对象上被按下 |
onmouseup | 当某个鼠标按键在某个对象上被松开 |
onmousemove | 当某个鼠标按键在某个对象上被移动 |
onmouseenter | 当鼠标进入某个对象(相似事件onmouseover) |
onmouseleave | 当鼠标离开某个对象(相似事件onmouseout) |
常见的键盘事件监听
事件名 | 事件描述 |
---|---|
onkeypress | 当某个键盘的键被按下(系统按钮无法得到识别) |
onkeydown | 当某个键盘的键被按下(系统按钮可以识别,并且会先于onkeypress发生) |
onkeyup | 当某个键盘的键被松开 |
事件传播
当盒子嵌套时事件监听的执行顺序事件的传播是:先从外到内(捕获阶段),然后再从内到外(冒泡)
on
只监听冒泡阶段
addEventListener()
当第三个参数为false时,事件处理程序将在事件冒泡阶段执行。如果不传递第三个参数,默认为false,即在事件冒泡阶段执行。
d.addEventListener('click',()=>{
// true 监听捕获阶段
// false,不设置 监听冒泡阶段
},true)
事件对象
- 事件处理函数提供一个形式参数,它是一个对象,封裝了本次事件的细节
- 这个参数通常用单词 event 或字母 e 表示
鼠标位置
属性 | 属性描述 |
---|---|
clientX | 鼠标指针相对于浏览器的水平坐标 |
clientY | 鼠标指针相对于浏览器的垂直坐标 |
pageX | 鼠标指针相对于整张网页的水平坐标 |
pageY | 鼠标指针相对于整张网页的垂直坐标 |
offsetX | 鼠标指针相对于事件源元素的水平坐标 |
offsetY | 鼠标指针相对于事件源元素的垂直坐标 |
当鼠标移入黑色区域便会显示该位置的坐标(相对于事件源元素)
e.charCode 和 e.keyCode 属性
e.charCode
属性通常用于 onkeypress
事件中,表示用户输入的字符的“字符码”
e.keyCode
属性通常用于 onkeydown
事件和 onkeyup
中,表示用户按下的按键的“键码“
按方向键可以控制页面上的盒子移动
e.preventDefault()方法
e.preventDefault()方法用来阻止事件产生的”默认动作“
一些特殊的业务需求,需要阻止事件的“默认动作”
制作一个文本框,只能让用户在其中输入小写字母和数字,其他字符输入没有效果
e.stopPropagation()方法
用来阻止事件继续传播
制作一个弹出层:点击按钮显示弹出层,点击网页任意地方,弹出层关闭
事件委托(代理)
提示
e.target
指向的是触发事件的元素
e.currentTarget
指向的是添加监听事件的元素
利用事件冒泡机制,将后代元素事件委托给祖先元素
动态绑定事件
事件委托的使用场景
当有大量类似元素需要批量添加事件监听时,使用事件委托可以减少内存开销
当有动态元素节点上树时,使用事件委托可以让新上树的元素具有事件监听
定时器和延时器
定时器
setInterval()
函数可以重复调用一个函数,在每次调用之间具有固定的时间间隔setInterval()
函数可以接收第 3、4…个参数,它们将按顺序传入函数ClearInterval()
函数可以清除一个定时器,需要传入定义器的变量
延时器
setTimeout()
函数可以设置一个延时器,当指定时间到了之后,会执行函数一次,不再重复执行clearTimeout()
函数可以清除延时器