DOM小结

####节点的属性

Node.textContent

Node.textContent 返回当前节点和所有后代节点的文本内容,会忽略HTML标签

1
2
3
<div id="x">Tom is a <span>handsome</span> boy!</div>
----
document.getElementById('x').textContent //Tom is a handsome boy! 这里包含了子节点span!
Node.baseURI

Node.baseURI 返回一个字符串,表示当前网页的绝对路径,如果无法取到这个值,返回null

1
2
3
4
// 当前网页的网址为
// http://www.example.com/index.html
document.baseURI
// "http://www.example.com/index.html"

#####Node.ownerDocument

Node.ownerDocument 返回当前节点所在的顶层文档对象。document 对象的ownerDocument属相,返回null。

Node.nextSibling && Node.previousSibling / Element.nextElementSibling & Element.previousElementSibling

Node.nextSibling 返回后面的第一个兄弟节点,如果没有则返回null,包括文本节点

区别Element.nextElementSibling属性返回当前HTML元素节点的后一个同级HTML元素节点,如果没有则返回null

:该属性包括文本节点和评论节点,所以当前节点后面有空格的话,会返回一个文本节点,内容为空格。!!

1
2
3
4
5
// html代码如下
// <a><b1 id="b1"/><b2 id="b2"/></a>
document.getElementById("b1").previousSibling // null
document.getElementById("b2").previousSibling.id // "b1"
Node.parentNode

返回当前节点的父节点。document的父节点为null。

#####Node.parentElement

返回当前节点的父Element节点。如果当前节点没有父节点,或者父节点类型不是Element节点,则返回null

Node.childNodes && Element.children
  • 返回一个NodeList集合,成员包括当前节点的所有子节点。由于NodeList对象是一个动态集合,一旦子节点发生变化,立刻会反映在返回结果之中。

:包含了text节点和comment节点

1
2
3
4
5
6
7
8
9
<body>
<ul id="x">
<li>123</li>
<li>12344</li>
<li>432</li>
</ul>
</body>
------------
document.getElementById('x').childNodes //[text, li, text, li, text, li, text] 包含了回车
  • 返回一个包含当前元素节点的所有子元素HTMLCollection对象,它只包含HTML元素类型,不包含其他类型的子节点。
Node.firstChild && Node.lastChild / Element.firstElementChild & Element.lastElementChild

返回当前节点的第一个子节点,如果当前节点没有子节点,则返回null包括文本节点

然而Element.firstElementChild 返回的是第一个HTML节点,不包括文本节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<p id="para-01"><span>First span</span></p>
<script type="text/javascript">
console.log(
document.getElementById('para-01').firstChild.nodeName
) // "span"
</script>
--------------
<p id="para-01">
<span>First span</span>
</p>
<script type="text/javascript">
console.log(
document.getElementById('para-01').firstChild.nodeName
) // "#text"
</script>

节点的方法

Node.appendChild()

方法接受一个节点对象作为参数,将其作为最后一个子节点,插入当前节点。

1
2
var p = document.createElement('p')
document.appendChild(p)

*如果参数节点是DOM中已经存在的节点,appendChild方法会将其从原来的位置,移动到新位置。

Node.hasChildNodes() && Node.contains()

返回一个布尔值,表示当前节点是否有子节点

返回一个布尔值,表示参数节点是否为当前节点的后代节点。(自身节点返回true nodeA.contains(nodeA))

Node.cloneNode()

用于克隆一个节点。它接受一个布尔值作为参数,表示是否同时克隆子节点,默认是false

需要注意的是,克隆一个节点,会拷贝该节点的所有属性,但是会丧失addEventListener方法。也会克隆两个有相同ID属性的HTML元素。

Node.insertBefore()

Node.insertBefore在当前节点的某个子节点之前再插入一个子节点。返回被插入的新节点。

语法:var insertedElement = parentElement.insertBefore(newElement, referenceElement);

如果referenceElementnullnewElement将被插入到子节点的末尾如果newElement已经在DOM树中,newElement首先会从DOM树中移除。

  • insertedElement 是被插入的节点,即 newElement
  • parentElement 是新插入节点的父节点
  • newElement 是被插入的节点
  • referenceElement 在插入newElement之前的那个节点
1
2
3
4
5
6
7
8
9
10
11
12
<div>
<span id="childElement">foo bar</span>
</div>
<script>
var sp1 = document.createElement("span");
var sp2 = document.getElementById("childElement");
sp2.parentNode.insertBefore(sp1, sp2);
</script>
--------------
#如果要sp1 插入到 sp2 后面
parentDiv.insertBefore(sp1, sp2.nextSibling)
Node.removeChild()

接受一个子节点作为参数,用于从当前节点移除该子节点。它返回被移除的子节点。

1
2
3
4
5
移除当前所有的子节点
var element=document.getElementById('div')
while(element.firstChild){
element.removeChild(element.firstChild)
}
Node.replaceChild()

语法:replacedNode = parentNode.replaceChild(newChild, oldChild)

1
2
3
4
var divA = document.getElementById('A')
var newSpan = document.createElement('span')
newSpan.textContent = 'Hello World!'
divA.parentNode.replaceChild(newSpan, divA)

Document节点

  • document.links 属性返回当前文档所有设定了href属性的aarea元素。
  • document.forms 属性返回页面中所有表单元素form
  • document.images 属性返回页面所有图片元素(即img标签)。

:如果一个元素有idname属性,就可以直接引用。

1
2
3
4
<a href="www.baidu.com" id="a">1</a>
<a href="www.qq.com" name="b">2</a>
---------
document.links.a.textContent //1
1
2
3
form表单的name属性可以直接引用
<form name="c">123</form>
document.c.textContent === document.forms.c.textContent //123
document.documentURI && document.URL

都返回一个字符串,表示当前文档的网址。documentURI属性可用于所有文档(包括 XML 文档),URL属性只能用于 HTML 文档。

还有类似的document.baseURI

document.domain

返回当前文档的域名

1
2
https://www.baidu.com/s?wd=Array.split%20mdn&rsv_spt=1
document.domain //www.baidu.com
document.lastModified

返回当前文档最后修改的时间戳,格式为字符串。字符串是不能比较的,用Date.parse()方法转换成时间戳才能进行比较

1
2
3
if (Date.parse(doc1.lastModified) > Date.parse(doc2.lastModified)) {
// ...
}
document.location
1
2
3
4
5
6
7
8
9
10
11
12
##location的属性
// 当前网址为 http://user:passwd@www.example.com:4097/path/a.html?x=111#part1
document.location.href // "http://user:passwd@www.example.com:4097/path/a.html?x=111#part1"
document.location.protocol // "http:"
document.location.host // "www.example.com:4097"
document.location.hostname // "www.example.com"
document.location.port // "4097"
document.location.pathname // "/path/a.html"
document.location.search // "?x=111"
document.location.hash // "#part1" //网页的位置
document.location.user // "user"
document.location.password // "passwd"
1
2
3
4
5
6
7
##location的方法:
##location.assign() location.reload() location.toString()===document.location.href
document.location.assign('http://www.google.com') // 跳转到另一个网址
document.location.reload(true) // 优先从服务器重新加载
document.location.reload(false) // 优先从本地缓存重新加载(默认值)
document.location.replace('http://www.google.com') // 跳转到新网址,并将取代掉history对象中的当前记录。浏览器history对象就会用新的网址,取代当前网址,这样的话,“后退”按钮就不会回到当前网页了。
document.location.toString() // 将location对象转为字符串,等价于document.location.href
1
2
3
4
5
6
7
8
9
10
11
#如果将新的网址赋值给location对象,网页就会自动跳转到新网址。
document.location = 'http://www.example.com'
// 等同于
document.location.href = 'http://www.example.com'
document.assign('http://example.com')
----------------
#也可以指定相对URL
document.location = 'page2.html'
-----------
#跳转到锚点处
document.location="#top"

#####document.referrer , document.title , document.characterSet

  • document.referrer属性返回一个字符串,表示当前文档的访问来源,如果是无法获取来源或是用户直接键入网址,而不是从其他网页点击,则返回一个空字符串。document.referre的值,总是与HTTP头信息的Referer保持一致,但是它的拼写有两个r
  • document.title属性返回当前文档的标题,该属性是可写的。document.title = '新标题'
  • document.characterSet属性返回渲染当前文档的字符集,比如UTF-8
document.readyState

返回当前文档的状态,共有三种可能的值。

  • loading:加载HTML代码阶段(尚未完成解析)
  • interactive:加载外部资源阶段时
  • complete:加载完成时
1
2
3
4
5
6
7
8
9
10
11
12
// 基本检查
if (document.readyState === 'complete') {
// ...
}
// 轮询检查
var interval = setInterval(function() {
if (document.readyState === 'complete') {
clearInterval(interval);
// ...
}
}, 100);

查找节点

document.querySelector() && document.queryselectorAll() /Element.querySelector() & Element.querySelectorAll()

document.querySelector方法接受一个CSS选择器作为参数,返回匹配该选择器的元素节点。如果有多个节点满足匹配条件,则返回第一个匹配的节点。如果没有发现匹配的节点,则返回null

document.querySelectorAll() 方法返回NodeList对象,有多个选择器可以用逗号分开

1
2
var elements = document.querySelectorAll('div.a,.topBar')
//同时选中class为a的div元素 和 class为topBar的元素数组集合

需要注意的是,浏览器执行querySelector方法时,是先在全局范围内搜索给定的CSS选择器,然后过滤出哪些属于当前元素的子元素。因此,会有一些违反直觉的结果,请看下面的HTML代码。

1
2
3
4
5
6
7
8
<div>
<blockquote id="outer">
<p>Hello</p>
<div id="inner">
<p>World</p>
</div>
</blockquote>
</div>

那么,下面代码实际上会返回第一个p元素,而不是第二个。

1
2
3
var outer = document.getElementById('outer');
outer.querySelector('div p')
// <p>Hello</p>
document.getElementsByTagName() / Element.getElementsByTagName()

方法返回所有指定HTML标签的元素,返回值是一个类似数组的HTMLCollection对象。

:HTML元素本身也定义了getElementsByTagName方法,这个方法不仅可以在document对象上调用,也可以在任何元素节点上调用。

1
2
var p = document.getElementsByTagName('p')
var span = p.getElementsByTagName('span')
document.getElementsByClassName() / Element.getElementsByClassName()

和上面一样,可以在任何元素节点上调用该方法

1
2
var elements = document.getElementsByClassName('foo bar')
//这里同时满足class为foo和bar的节点。参数写法上与document.querySelector()区分开,

#####document.getElementById()

:只能用在document上,不能用在其他元素身上

1
2
document.querySelector('#top')
document.getElementById('top') //这种选择效率比上面这种方法高很多
document.getElementsByName()

document.getElementsByName方法用于选择拥有name属性的HTML元素(比如<form><radio><img><frame><embed><object>等),返回一个类似数组的的对象(NodeList对象的实例)

1
//<form></form>

  • Element.querySelector()

  • Element.querySelectorAll()

  • Element.getElementsByTagName()
  • Element.getElementsByClassName()

上面四个方法只返回Element子节点,因此可以采用链式写法。

1
2
3
document
.getElementById('header')
.getElementsByClassName('a')

生成节点

document.createElement()

用来生成网页元素的节点,参数为标签名。

1
document.createElement('div')
document.createTextNode()

用来生成文本节点,参数为文本的内容。

1
2
3
var newDiv = document.createElement('div')
var newContent = document.createTextNode('Hello')
newDiv.appendChild(newContent)

这个方法可以确保返回的节点,被浏览器当作文本渲染,而不是当作HTML代码渲染。因此,可以用来展示用户的输入,避免XSS攻击。

1
2
3
4
var div = document.createElement('div');
div.appendChild(document.createTextNode('<span>Foo & bar</span>'));
console.log(div.innerHTML)
// &lt;span&gt;Foo &amp; bar&lt;/span&gt;
innerHTML & outerHTML & textContent的区别
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<body>
<ul id='a'>
<li>花</li>
<li>草</li>
</ul>
</body>
-------------
var innerHtml = document.getElementById('a').innerHTML
console.log(innerHTML) //注意innerHTML的写法
//<li>花</li>
<li>草</li> 会返回不包括父标签的内容,包含标签
-----------
var outerHTML = document.getElementById('a').outerHTML
console.log(outerHTML)
//<ul id="a">
<li>花</li>
<li>草</li>
</ul> 返回包含父标签的所有html内容
--------------
var textContent = document.getElementById('a').textContent
console.log(textContent)
//花
草 返回所有的文本内容

属性操作

document.createAttribute()

生成一个新的属性对象节点

1
2
3
4
5
6
7
var node = document.getElementById("div1")
var a = document.createAttribute("my_attrib")
a.value = "newVal"
node.setAttributeNode(a)
// 等同于
var node = document.getElementById("div1")
node.setAttribute("my_attrib", "newVal")
Element.getAttribute(name)

返回当前元素节点的指定属性。如果指定属性不存在,则返回null

1
2
3
// <div id="div1" align="left">
var div = document.getElementById('div1');
div.getAttribute('align') // "left"
Element.setAttribute(name,value)

用于为当前元素节点新增属性。如果同名属性已存在,则相当于编辑已存在的属性。

1
2
3
4
5
var d = document.getElementById('d1');
d.setAttribute('align', 'center');
------
var myImage = document.querySelector('img');
myImage.setAttribute('src', 'path/to/example.png');
Element.hasAttribute(name)

返回一个布尔值,表示当前元素是否包含指定属性

1
2
3
4
var d = document.getElementById('div1')
if(d.hasAttribute('align')){
d.setAttribute('align','center')
}
Element.removeAttribute(name)

从当前节点移除属性

1
2
3
4
//<div id="div1" align="left" width="200px">
document.getElementById('div1').removeAttribute('align')
// 现在的HTML代码为
// <div id="div1" width="200px">
dataset属性

有时需要再HTML元素上附加数据,可以使用标准提供的data-属性。然后使用节点对象的dataset属性来操作元素标签的data-\属性

1
2
3
4
5
6
<div id="mydiv" data-foo="bar"></div>
var a = document.getElementById('mydiv')
a.dataset.foo //bar
a.dataset.foo = 'baz' //这个属性可以用来读写
-------也可以直接用delete删除该属性
delete a.dataset.foo

除了dataset属性,也可以用getAttribute('data-foo')removeAttribute('data-foo')setAttribute('data-foo')hasAttribute('data-foo')等方法操作data-*属性。

注意,data-后面的属性名有限制,只能包含字母、数字、连词线(-)、点(.)、冒号(:)和下划线(_)。而且,属性名不应该使用AZ的大写字母,比如不能有data-helloWorld这样的属性名,而要写成data-hello-world

转成dataset的键名时,连词线后面如果跟着一个小写字母,那么连词线会被移除,该小写字母转为大写字母,其他字符不变。反过来,dataset的键名转成属性名时,所有大写字母都会被转成连词线+该字母的小写形式,其他字符不变。比如,dataset.helloWorld会转成data-hello-world

Element对象

#####Element.className ,Element.classList

className属性用来读写当前元素节点的class属性。它的值是一个字符串,每个class之间用空格分割。

classList属性则返回一个类似数组的对象,当前元素节点的每个class就是这个对象的一个成员。

1
2
3
4
5
6
7
8
9
10
11
12
<div class="one two three" id="myDiv"></div>
document.getElementById('myDiv').className
// "one two three"
--------------
document.getElementById('myDiv').classList
// {
// 0: "one"
// 1: "two"
// 2: "three"
// length: 3
// }
  • Element.classList.add():增加一个class。
  • Element.classList.remove():移除一个class。
  • Element.classList.contains():检查当前元素是否包含某个class。
  • Element.classList.toggle():将某个class移入或移出当前元素。
  • Element.classList.item():返回指定索引位置的class。
  • Element.classList.toString():将class的列表转为字符串。
1
2
3
4
5
6
7
myDiv.classList.add('myCssClass');
myDiv.classList.add('foo', 'bar');
myDiv.classList.remove('myCssClass');
myDiv.classList.toggle('myCssClass'); // 如果myCssClass不存在就加入,否则移除
myDiv.classList.contains('myCssClass'); // 返回 true 或者 false
myDiv.classList.item(0); // 返回第一个Class
myDiv.classList.toString();
Element.closest()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<p>
<div id="div-01">Here is div-01
<div id="div-02">Here is div-02
<div id="div-03">Here is div-03</div>
</div>
</div>
</p>
var el = document.getElementById('div-03');
var r1 = el.closest("#div-02");
// 返回 id 为 div-02 的那个元素
var r2 = el.closest("div div");
// 返回最近的拥有 div 祖先元素的 div 祖先元素,这里的话就是 div-03 元素本身
var r3 = el.closest("p > div");
// 返回最近的拥有父元素 p 的 div 祖先元素,这里的话就是 div-01
var r4 = el.closest(":not(div)");
// 返回最近的非 div 的祖先元素,这里的话就是最外层的 p

盒模型相关属性

#####Element.clientHeight, Element.clientWidth

Element.clientWidth 属性表示元素的内部宽度,以像素计。该属性包括内边距,但不包括垂直滚动条(如果有)、边框和外边距。

Element.clientLeft ,Element.clientTop

返回元素周围边框的厚度即border的宽度,不包括padding和margin

#####Element.scrollHeight ,Element.scrollWidth

Element.scrollHeight 是计量元素内容高度的只读属性,包括overflow样式属性导致的视图中不可见内容。没有垂直滚动条的情况下,scrollHeight值与元素视图填充所有内容所需要的最小值clientHeight相同。包括元素的padding,但不包括元素的margin.

1
2
Element.scrollHeight 是计量元素内容高度的只读属性,包括overflow样式属性导致的视图中不可见内容。没有垂直滚动条的情况下,scrollHeight值与元素视图填充所有内容所需要的最小值clientHeight相同。包括元素的padding,但不包括元素的margin.
element.scrollHeight - element.scrollTop === element.clientHeight
Element.scrollLeft, Element.scrolltop

Element.scrollLeft属性表示网页元素的水平滚动条向右侧滚动的像素数量,Element.scrollTop属性表示网页元素的垂直滚动条向下滚动的像素数量。对于那些没有滚动条的网页元素,这两个属性总是等于0。

如果要查看整张网页的水平的和垂直的滚动距离,要从document.documentElement元素上读取。

1
2
document.documentElement.scrollLeft
document.documentElement.scrollTop

这两个属性都可读写,设置该属性的值,会导致浏览器将指定元素自动滚动到相应的位置。

Element.offsetHeight, Element.offsetWidth

这两个属性值包括PaddingBorder、以及滚动条。

1
2
3
4
5
6
7
8
9
10
11
12
#整张网页的高度,可以在document.documentElement和document.body上读取。
// 网页总高度
document.documentElement.offsetHeight
document.body.offsetHeight
// 网页总宽度
document.documentElement.offsetWidth
document.body.offsetWidth
--------------
//视口高度/宽度
window.innerHeight/innerWidth //包括滚动条
document.documentElement.clientHeight/clientWidth //不包括滚动条

#####Element.getBoundingClientRect()

Element.getBoundingClientRect方法返回一个对象,该对象提供当前元素节点的大小、位置等信息,基本上就是CSS盒状模型提供的所有信息。

1
var rect = obj.getBoundingClientRect();

上面代码中,getBoundingClientRect方法返回的rect对象,具有以下属性(全部为只读)。

  • x:元素左上角相对于视口的横坐标
  • left:元素左上角相对于视口的横坐标,与x属性相等
  • right:元素右边界相对于视口的横坐标(等于x加上width
  • width:元素宽度(等于right减去left
  • y:元素顶部相对于视口的纵坐标
  • top:元素顶部相对于视口的纵坐标,与y属性相等
  • bottom:元素底部相对于视口的纵坐标
  • height:元素高度(等于y加上height

由于元素相对于视口(viewport)的位置,会随着页面滚动变化,因此表示位置的四个属性值,都不是固定不变的。如果想得到绝对位置,可以将left属性加上window.scrollXtop属性加上window.scrollY

注意,getBoundingClientRect方法的所有属性,都把边框(border属性)算作元素的一部分。也就是说,都是从边框外缘的各个点来计算。因此,widthheight包括了元素本身 + padding + border

获取某个网页元素距离视口左上角的坐标

1
2
3
4
5
// 网页元素左上角的视口横坐标
Element.getBoundingClientRect().left
// 网页元素左上角的视口纵坐标
Element.getBoundingClientRect().top
1
2
3
4
5
6
7
某个网页元素距离网页左上角的坐标,使用视口坐标加上网页滚动距离。
// 网页元素左上角的网页横坐标
Element.getBoundingClientRect().left + document.documentElement.scrollLeft
// 网页元素左上角的网页纵坐标
Element.getBoundingClientRect().top + document.documentElement.scrollTop
1
2
3
4
5
6
#网页目前滚动的距离,可以从document.documentElement节点上得到。
// 网页滚动的水平距离
document.documentElement.scrollLeft
// 网页滚动的垂直距离
document.documentElement.scrollTop
Element.getClientRects()

Element.getClientRects方法返回一个类似数组的对象,里面是当前元素在页面上形成的所有矩形。每个矩形都有bottomheightleftrighttopwidth六个属性,表示它们相对于视口的四个坐标,以及本身的高度和宽度。

1
2
3
4
5
<span id="inline">
Hello World
Hello World
Hello World
</span>

上面代码是一个行内元素<span>,如果它在页面上占据三行,getClientRects方法返回的对象就有三个成员,如果它在页面上占据一行,getClientRects方法返回的对象就只有一个成员。

1
2
3
4
5
6
7
var el = document.getElementById('inline');
el.getClientRects().length // 3
el.getClientRects()[0].left // 8
el.getClientRects()[0].right // 113.908203125
el.getClientRects()[0].bottom // 31.200000762939453
el.getClientRects()[0].height // 23.200000762939453
el.getClientRects()[0].width // 105.908203125

这个方法主要用于判断行内元素是否换行,以及行内元素的每一行的位置偏移。

Element.insertAdjacentHTML()

语法:element.insertAdjacentHTML(position, text)

指定位置共有四个。

  • beforebegin:在当前元素节点的前面。
  • afterbegin:在当前元素节点的里面,插在它的第一个子元素之前。
  • beforeend:在当前元素节点的里面,插在它的最后一个子元素之后。
  • afterend:在当前元素节点的后面。
1
2
3
4
5
// 原来的HTML代码:<div id="one">one</div>
var d1 = document.getElementById('one');
d1.insertAdjacentHTML('afterend', '<div id="two">two</div>');
// 现在的HTML代码:
// <div id="one">one</div><div id="two">two</div>

该方法不是彻底置换现有的DOM结构,这使得它的执行速度比innerHTML操作快得多。

1
d1.innerHTML = '<div id="two">two</div>'
Element.remove()

Element.remove方法用于将当前元素节点从DOM树删除。

1
2
var el = document.getElementById('div-01');
el.remove();

####Text节点

通常我们使用Node节点的firstChildnextSibling等属性获取Text节点,或者使用Document节点的createTextNode方法创造一个Text节点。