在我们工作中大多数DOM脚本的主要任务就是在DOM文档中插入,删除和移动节点。W3C DOM 提供了4种方法来修改文档树。常用的是appendChild()和insertBefore(),而removeChild() 和replaceChild()很少用到。
在我们学习之前,我还是把总结好的DOM知识体系表放在前面以方便我们查阅。
Node接口定义的节点类型都包含的特性和方法
特性和方法后面的 “冒号:” 紧跟的单词是“返回值类型 ”
Node
属性
-
遍历节点(短途旅行):
-
parentNode : Node
-
firstChild : Node
-
lastChild : Node
-
nextSibling : Node
-
previousSibling : Node
-
childNodes : NodeList
-
节点信息:
-
nodeName :String
-
nodeType :number
-
nodeValue :String
-
返回一个节点的根元素(文档对象):
-
ownerDocument : Document
-
包含了代表一个元素的特性的Attr对象;仅用于Element节点:
-
attributes : NamedNodeMap
-
获取对象层次中的父对象:
-
parentElement [IE] :Node
方法
-
修改文档树:
-
appendChild(Node newChild) : Node
-
insertBefore(Node newChild, Node refChild) : Node
-
removeChild(Node oldChild): Node
-
replaceChild(Node newChild, Node refChild) : Node
-
克隆一个节点:
-
cloneNode(boolean deep) : Node
-
删除一个子节点:
-
removeNode(boolean removeChildren) : Node
-
判断childNodes包含是否包含节点:
-
hasChildNodes() : boolean
Node
-
Document
-
属性
-
自己的:
-
documentElement : Element
-
继承 Node :
-
attributes, childNodes, firstChild, lastChild, nextSibling, nodeName, nodeType, nodeValue, ownerDocument, parentElement, parentNode, previousSibling
-
方法
-
自己的:
-
-
创建元素:
-
createElement(String tagName) : Element
-
createTextNode(String data) : Text
-
查找元素:
-
getElementById(String elementId) : Element
-
getElementsByTagName(String tagname) : NodeList
-
继承 Node :
-
appendChild, cloneNode, hasChildNodes, insertBefore, removeChild, removeNode, replaceChild
-
Element
-
属性
-
自己的:
-
tagName: String
-
继承 Node :
-
attributes, childNodes, firstChild, lastChild, nextSibling, nodeName, nodeType, nodeValue, ownerDocument, parentElement, parentNode, previousSibling
-
方法
-
自己的:
-
-
属性的读写:
-
getAttribute(String name) : String
-
setAttribute(String name, String value) : void
-
-
其它:
-
getElementsByTagName(String name) Stub : NodeList
-
normalize() Stub : void
-
removeAttribute(String name) : void
-
继承 Node :
-
appendChild, cloneNode, hasChildNodes, insertBefore, removeChild, removeNode, replaceChild
一般用法
修改文档提供的4个方法,都是指向它们所作用的节点的引用。
下面我还是以我的导航条 HTML页面作为范例来解释这4个方法的应用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<div
id
=
"menu"
>
<h1
>
我的导航条</
h1
>
<ul
id
=
"nav"
>
<li
><a
href
=
"#"
>
HOME</
a
></
li
>
<li
><a
href
=
"#"
>
(X)Html / Css</
a
></
li
>
<li
><a
href
=
"#"
>
Ajax / RIA</
a
></
li
>
<li
><a
href
=
"#"
>
GoF</
a
></
li
>
<li
><a
href
=
"#"
>
JavaScript</
a
></
li
>
<li
><a
href
=
"#"
>
JavaWeb</
a
></
li
>
<li
><a
href
=
"#"
>
jQuery</
a
></
li
>
<li
><a
href
=
"#"
>
MooTools</
a
></
li
>
<li
><a
href
=
"#"
>
Python</
a
></
li
>
<li
><a
href
=
"#"
>
Resources</
a
></
li
>
</
ul
>
</
div
>
|
appendChild()
appendChild()方法让你添加一个节点并使其成为某个元素的最后一个子节点。
如果添加的该节点已经存在于文档中,它会从当前位置移除。该节点的子节点保持不变,它们也被一起移动到新的位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<
script type=
"text/javascript"
>
window.onload
=
function
(
)
{
/*为一个元素添加子元素*/
var
nav=
document.getElementById
(
"nav"
)
;
//创建一个li新元素
var
newChild=
document.createElement
(
'li'
)
;
//创建一个a 新元素
var
newLink=
document.createElement
(
'a'
)
//创建一个 Text 节点
var
newText=
document.createTextNode
(
'My Wiki'
)
;
//把Text添加到a元素节点中
newLink.appendChild
(
newText)
;
//给a元素节点设置属性href和内容
newLink.setAttribute
(
'href'
,
"#"
)
;
//把a元素节点添加到新的li元素节点中
newChild.appendChild
(
newLink)
;
//把新的li元素节点添加到 ul 元素节点里
nav.appendChild
(
newChild)
;
/*<li>从原始位置上被移除,成为ul的最后一个子节点。它的a 元素节点和文本节点HODE也被移了过来*/
nav_list=
nav.getElementsByTagName
(
"li"
)
;
//返回相同的一组元素
nav.appendChild
(
nav_list[
0
]
)
;
}
</
script>
|
创建新DOM元素的通用函数
1
2
3
4
5
6
7
8
|
<
script type=
"text/javascript"
>
function
create(
elem )
{
return
document.createElementNS
?
document.createElementNS
(
'http://www.w3.org/1999/xhtml'
,
elem )
:
document.createElement
(
elem )
;
}
</
script>
|
我们看到结果:
添加好的子节点
从原始位置上被移除,成为ul的最后一个子节点
insertBefore()
insertBefore()方法允许你在其他节点的前面插入一个节点,所以当你想要添加一个子节点,但又不希望该节点成为最后一个子节点的时候,就可以使用此方法。
就像appendChild()方法一样,如果插入的节点已经存在于文档之中,它会被从当前位置移除,而且该节点在被插入之后乃保持它的子节点结构。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<
script type=
"text/javascript"
>
window.onload
=
function
(
)
{
var
nav=
document.getElementById
(
"nav"
)
;
nav_list=
nav.getElementsByTagName
(
"li"
)
;
//返回相同的一组元素
//第一个节点
var
x=
nav_list[
0
]
;
//最后一个节点
var
y=
nav_list[
nav_list.length
-
1
]
//在x元素对象之前插入y元素对象
nav.insertBefore
(
y,
x)
;
//在x元素对象之前插入新生产的newChild元素对象
nav.insertBefore
(
newChild,
x)
;
//newChild元素对象的创建请参考上面的代码
}
</
script>
|
在其他节点的前面插入一个节点
replaceChild()
replaceChild()方法允许你把一个节点替换为另一个节点。
就像appendChild()和insertBefore()一样,如果插入的节点已经存在于文档之中,它会被从当前位置移除,而且该节点在被插入之后乃保持它的子节点结构。
1
2
3
4
5
6
7
8
9
10
|
<
script type=
"text/javascript"
>
window.onload
=
function
(
)
{
var
nav=
document.getElementById
(
"nav"
)
;
nav_list=
nav.getElementsByTagName
(
"li"
)
;
//返回相同的一组元素
//第一个节点对象
var
x=
nav_list[
0
]
;
//x节点对象被newChild新节点对象替换了
nav.replaceChild
(
newChild,
x)
;
}
</
script>
|
把一个节点替换为另一个节点
removeChild()
removeChild()方法允许你移除一个节点以及它的子节点们。
1
2
3
4
5
6
7
8
9
10
|
<
script type=
"text/javascript"
>
window.onload
=
function
(
)
{
var
nav=
document.getElementById
(
"nav"
)
;
nav_list=
nav.getElementsByTagName
(
"li"
)
;
//返回相同的一组元素
//最后一个节点
var
y=
nav_list[
nav_list.length
-
1
]
//移除最后面的一个节点
nav.removeChild
(
y)
;
}
</
script>
|
你移除一个节点以及它的子节点们
移除所有的子节点
有的时候你需要把一个元素清除干净;你想在添加新节点前清除原来的所有子点。
有两个简单的方法来做这件事情:
1
2
3
4
5
6
7
8
9
10
11
12
|
<
script type=
"text/javascript"
>
while
(
x.childNodes
[
0
]
)
{
x.removeChild
(
x.childNodes
[
0
]
)
;
}
/*
//我们可以使用firstChild来代替childNodes[0]
while (x.firstChild){
x.removeChild(x.firstChild);
}
* /
</script>
|
这是一个简单的while()循环,只要元素存在第一个节点(childNodes[0]),它就移除这个节点,接着节点集合立即更新。所以(原来的)第二个节点成为了第一个节点,循环就会一直重复,直到X没有子节点为止。
另一个方法就简单了
1
2
3
|
<
script type=
"text/javascript"
>
x.innerHTML
=
''
;
</
script>
|
辅助函数
appendChild()和insertBefore()都有2个参数,但是我们在应用的时候,还要注意参数的先后顺序。
既然这么麻烦我们还是自己写一些辅助函数来代替原有的appendChild()和insertBefore()。
在另一个元素之前插入元素的函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<
script type=
"text/javascript"
>
//insertBefore()的代替方法
function
before(
parent,
before,
elem )
{
// Check to see if no parent node was provided
//检查parent是否传入
if
(
elem ==
null
)
{
elem =
before;
before =
parent;
parent =
before.parentNode
;
}
// Get the new array of elements
//获取元素的新数组
var
elems =
checkElem(
elem )
;
// Move through the array backwards,
// because we’re prepending elements
//向后遍历数组
//因为我们向前插入元素
for
(
var
i =
elems.length
-
1
;
i >=
0
;
i--
)
{
parent.insertBefore
(
elems[
i]
,
before )
;
}
}
</
script>
|
为另一个元素添加一个子元素:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<
script type=
"text/javascript"
>
//appendChild()的代替方法
function
append(
parent,
elem )
{
// Get the array of elements
//获取元素数组
var
elems =
checkElem(
elem )
;
// Append them all to the element
//把它们所有都追加到元素中
for
(
var
i =
0
;
i <=
elems.length
;
i++
)
{
parent.appendChild
(
elems[
i]
)
;
}
}
</
script>
|
before和append的辅助函数:
1
2
3
4
5
6
7
8
|
<
script type=
"text/javascript"
>
function
checkElem(
elem )
{
// If only a string was provided, convert it into a Text Node
//如果只提供字符串,那就把它转换为文本节点
return
elem &&
elem.constructor
==
String ?
document.createTextNode
(
elem )
:
elem;
}
</
script>
|
注意:constructor的用法。
有时你可能需要对变量进行类型检查,或者判断变量是否已定义。有两种方法可以使用:typeof函数与constructor属性。
typeof可以检查到变量是否有定义,而construct只能检查已定义变量的类型。
移除所有的子节点的辅助函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<
script type=
"text/javascript"
>
function
empty(
elem )
{
while
(
elem.firstChild
)
{
remove(
elem.firstChild
)
;
}
/*
//我们可以使用firstChild来代替childNodes[0]
while (elem.childNodes[0])
remove(elem.childNodes[0]);
* /
}
function remove( elem ) {
if ( elem ) elem.parentNode.removeChild( elem );
}
</script>
|
下一节中我们开始讨论 W3C DOM 的创建和克隆元素的方法。