js - DOM编程核心

DOM Core常用部分:

DOM方法
创建节点:createElement(),createTextNode()
复制节点:cloneNode()
插入节点:appendChild(),insertBefore
删除节点:removeChild()
替换节点:replaceChild()
查找节点:getAttribute(),getElementById(),getElementsByTagName,hasChildNodes
设置节点属性:setAttribute()


DOM属性
节点的属性:nodeName,nodeType,nodeValue
遍历节点 树:childNodes,firstChild,lastChild,nextSibling,parentNode,previousSibling


下面给出这部分的简要用法,做个索引似帮助文档 
1.document.createElement("节点名"):新建一个节点

2.document.createTextNode("文本内容"):新建一个文本节点

3.节点.cloneNode(true|false):复制该节点,参数true则连同子结点一同复制,false则不复制子结点

4.节点.appendChild(子节点):在节点下添加子结点

5.父节点.insertBefore(新节点,参照点):在该父节点下的参照点前面插入新节点.通常父节点这样写:参照点.parentNode

6.父节点.removeChild(子结点):删除该父节点下指定的子结点,该子结点下的所有嵌套子结点都将被删除

7.父节点.replaceChild(新节点,旧节点):把该父节点下的指定子结点替换为新节点

8.节点.getAttribute("属性名"):搜索指定节点的属性名,返回该属性的属性值

9.document.getElementById("id名"):搜索文档中指定id名的节点,返回该节点对象

10.document.getElementsByTagName("标签名"):搜索文档中指定标签名的节点,返回一个节点对象列表(数组), 基数从0开始,具有length属性,表示数组长度

11.节点.hasChildNodes:该节点是否具有子结点,有,返回true,没有子结点返回false(比如文本节点和属性节点)

12.节点.setAttribute("属性名","属性值"):为该节点添加属性,若该属性已经存在则刷新属性值

13.节点.nodeName:根据节点类型区分
    元素节点:返回标签名(相当于tagName属性)
    文本节点:返回#text
    属性节点:返回属性名

14.节点.nodeType:返回节点类型,常用有一下三种:
    元素节点:返回1
    属性节点:返回2
    文本节点:返回3

15.节点.nodeValue:返回节点当前的值,根据节点类型区分:
    元素节点:返回null
    属性节点:返回属性值
    文本节点:返回文本内容

16.节点.childNodes:返回该节点下的所有一级子结点(前面有具体介绍过,这个属性在不同浏览器有不同解释)

17.节点.firstChild:返回该节点下的第一个子结点

18.节点.lastChild:返回该节点下的最后一个子结点

19.节点.nextSibling:返回该节点的下一个兄弟节点对象

20.节点.parentNode:返回该节点的父节点(肯定是一个元素节点,document节点的父节点为null)

21.节点.previousSibling:和nextSibling相对,返回该节点的上一个兄弟节点对象

在数据库中存储层次数据

 

无论你要构建自己的论坛,在你的网站上发布消息还是书写自己的cms [1]程序,你都会遇到要在数据库中存储层次数据的情况。同时,除非你使用一种像XML [2]的数据库,否则关系数据库中的表都不是层次结构的,他们只是一个平坦的列表。所以你必须找到一种把层次数据库转化的方法。

存储树形结构是一个很常见的问题,他有好几种解决方案。主要有两种方法:邻接列表模型和改进前序遍历树算法

在本文中,我们将探讨这两种保存层次数据的方法。我将举一个在线食品店树形图的例子。这个食品店通过类别、颜色和品种来组织食品。树形图如下:

1105_tree

本文包含了一些代码的例子来演示如何保存和获取数据。我选择PHP [3]来写例子,因为我常用这个语言,而且很多人也都使用或者知道这个语言。你可以很方便地把它们翻译成你自己用的语言。

邻接列表模型(The Adjacency List Model)

我们要尝试的第一个——也是最优美的——方法称为“邻接列表模型”或称为“递归方法”。它是一个很优雅的方法因为你只需要一个简单的方法来在你的树中进行迭代。在我们的食品店中,邻接列表的表格如下:

1105_table1

如你所见,对每个节点保存一个“父”节点。我们可以看到“Pear [4]”是“Green”的一个子节点,而后者又是“Fruit”的子节点,如此类推。根节点,“Food”,则他的父节点没有值。为了简单,我只用了“title”值来标识每个节点。当然,在实际的数据库中,你要使用数字的ID。

显示树

现在我们已经把树放入数据库中了,得写一个显示函数了。这个函数将从根节点开始——没有父节点的节点——同时要显示这个节点所有的子节点。对于这些子节点,函数也要获取并显示这个子节点的子节点。然后,对于他们的子节点,函数还要再显示所有的子节点,然后依次类推。

也许你已经注意到了,这种函数的描述,有一种普遍的模式。我们可以简单地只写一个函数,用来获得特定节点的子节点。这个函数然后要对每个子节点调用自身来再次显示他们的子节点。这就是“递归”机制,因此称这种方法叫“递归方法”。

<?php
// $parent 是我们要查看的子节点的父节点
// $level 会随着我们深入树的结构而不断增加,
//        用来显示一个清晰的缩进格式
function display_children($parent, $level) {
    // 获取$parent的全部子节点
    $result = mysql_query('SELECT title FROM tree '.
                           'WHERE parent="'.$parent.'";'); 

    // 显示每个节点
    while ($row = mysql_fetch_array($result)) {
        // 缩进并显示他的子节点的标题
        echo str_repeat('  ',$level).$row['title']."\n"; 

        // 再次调用这个函数来显着这个子节点的子节点
        display_children($row['title'], $level+1);
    }
}
?>

要实现整个树,我们只要调用函数时用一个空字符串作为$parent 和$level = 0: display_children('',0); 函数返回了我们的食品店的树状图如下:

Food
  Fruit
    Red
      Cherry
    Yellow
      Banana
  Meat
    Beef
    Pork

注意如果你只想看一个子树,你可以告诉函数从另一个节点开始。例如,要显示“Fruit”子树,你只要display_children('Fruit',0); while ($row = mysql_fetch_array($result)) { // 检查栈里面有没有元素 if (count($right)>0) { // 检查我们是否需要从栈中删除一个节点 while ($right[count($right)-1]<$row['rgt']) { array_pop($right); } } // 显示缩进的节点标题 echo str_repeat(' ',count($right)).$row['title']."\n"; // 把这个节点添加到栈中 $right[] = $row['rgt']; } } ?>

节点的路径

利用差不多的函数,我们也可以查询某个节点的路径如果你只知道这个节点的名字或者ID。例如,“Cherry”的路径是“Food”>“Fruit”>“Red”。要获得这个路径,我们的函数要获得这个路径,这个函数必须从最深的层次开始:“Cheery”。但后查找这个节点的父节点,并添加到路径中。在我们的例子中,这个父节点是“Red”。如果我们知道“Red”是“Cherry”的父节点。

<?php
// $node 是我们要查找路径的那个节点的名字
function get_path($node) {
    // 查找这个节点的父节点
    $result = mysql_query('SELECT parent FROM tree '.
                           'WHERE title="'.$node.'";');
    $row = mysql_fetch_array($result); 

    // 在这个array[5] 中保存数组
    $path = array(); 

    // 如果 $node 不是根节点,那么继续
    if ($row['parent']!='') {
        //  $node 的路径的最后一部分是$node父节点的名称
        $path[] = $row['parent']; 

        // 我们要添加这个节点的父节点的路径到现在这个路径
        $path = array_merge(get_path($row['parent']), $path);
    } 

    // 返回路径
    return $path;
}
?>

这个函数现在返回了指定节点的路径。他把路径作为数组返回,这样我们可以使用print_r(get_path('Cherry')); 来显示,其结果是:

Array
(
    [0] => Food
    [1] => Fruit
    [2] => Red
)

不足

正如我们所见,这确实是一个很好的方法。他很容易理解,同时代码也很简单。但是邻接列表模型的缺点在哪里呢?在大多数编程语言中,他运行很慢,效率很差。这主要是“递归”造成的。我们每次查询节点都要访问数据库。

每次数据库查询都要花费一些时间,这让函数处理庞大的树时会十分慢。

造成这个函数不是太快的第二个原因可能是你使用的语言。不像Lisp这类语言,大多数语言不是针对递归函数设计的。对于每个节点,函数都要调用他自己,产生新的实例。这样,对于一个4层的树,你可能同时要运行4个函数副本。对于每个函数都要占用一块内存并且需要一定的时间初始化,这样处理大树时递归就很慢了。

改进前序遍历树

现在,让我们看另一种存储树的方法。递归可能会很慢,所以我们就尽量不使用递归函数。我们也想尽量减少数据库查询的次数。最好是每次只需要查询一次。

我们先把树按照水平方式摆开。从根节点开始(“Food”),然后他的左边写上1。然后按照树的顺序(从上到下)给“Fruit”的左边写上2。这样,你沿着树的边界走啊走(这就是“遍历”),然后同时在每个节点的左边和右边写上数字。最后,我们回到了根节点“Food”在右边写上18。下面是标上了数字的树,同时把遍历的顺序用箭头标出来了。

1105_numbering

我们称这些数字为左值和右值(如,“Food”的左值是1,右值是18)。正如你所见,这些数字按时了每个节点之间的关系。因为“Red”有3和6两个值,所以,它是有拥有1-18值的“Food”节点的后续。同样的,我们可以推断所有左值大于2并且右值小于11的节点,都是有2-11的“Food”节点的后续。这样,树的结构就通过左值和右值储存下来了。这种数遍整棵树算节点的方法叫做“改进前序遍历树”算法。

在继续前,我们先看看我们的表格里的这些值:

1105_table2

注意单词“left”和“right”在SQL中有特殊的含义。因此,我们只能用“lft”和“rgt”来表示这两个列。(译注——其实Mysql中可以用“`”来表示,如“`left`”,MSSQL中可以用“[]”括出,如“[left]”,这样就不会和关键词冲突了。)同样注意这里我们已经不需要“parent”列了。我们只需要使用lft和rgt就可以存储树的结构。

获取树

如果你要通过左值和右值来显示这个树的话,你要首先标识出你要获取的那些节点。例如,如果你想获得“Fruit”子树,你要选择那些左值在2到11的节点。用SQL语句表达:

SELECT * FROM tree WHERE lft BETWEEN 2 AND 11;

这个会返回:

1105_table3

好吧,现在整个树都在一个查询中了。现在就要像前面的递归函数那样显示这个树,我们要加入一个ORDER BY子句在这个查询中。如果你从表中添加和删除行,你的表可能就顺序不对了,我们因此需要按照他们的左值来进行排序。

SELECT * FROM tree WHERE lft BETWEEN 2 AND 11 ORDER BY lft ASC;

就只剩下缩进的问题了。

要显示树状结构,子节点应该比他们的父节点稍微缩进一些。我们可以通过保存一个右值的一个栈。每次你从一个节点的子节点开始时,你把这个节点的右值添加到栈中。你也知道子节点的右值都比父节点的右值小,这样通过比较当前节点和栈中的前一个节点的右值,你可以判断你是不是在显示这个父节点的子节点。当你显示完这个节点,你就要把他的右值从栈中删除。要获得当前节点的层数,只要数一下栈中的元素。

<?php
function display_tree($root) {
    // 获得$root节点的左边和右边的值
    $result = mysql_query('SELECT lft, rgt FROM tree '.
                           'WHERE title="'.$root.'";');
    $row = mysql_fetch_array($result); 

    // 以一个空的$right栈开始
    $right = array(); 

    // 现在,获得$root节点的所有后序
    $result = mysql_query('SELECT title, lft, rgt FROM tree '. 

      'WHERE lft BETWEEN '.$row['lft'].' AND '.
                           $row['rgt'].' ORDER BY lft ASC;'); 

    // 显示每一行

如果运行这段代码,你可以获得和上一部分讨论的递归函数一样的结果。而这个函数可能会更快一点:他不采用递归而且只是用了两个查询

节点的路径

有了新的算法,我们还要另找一种新的方法来获得指定节点的路径。这样,我们就需要这个节点的祖先的一个列表。

由于新的表结构,这不需要花太多功夫。你可以看一下,例如,4-5的“Cherry”节点,你会发现祖先的左值都小于4,同时右值都大于5。这样,我们就可以使用下面这个查询:

SELECT title FROM tree WHERE lft < 4 AND rgt > 5 ORDER BY lft ASC;

注意,就像前面的查询一样,我们必须使用一个ORDER BY子句来对节点排序。这个查询将返回:

+-------+
| title |
+-------+
| Food  |
| Fruit |
| Red   |
+-------+

我们现在只要把各行连起来,就可以得到“Cherry”的路径了。

有多少个后续节点?How Many Descendants

如果你给我一个节点的左值和右值,我就可以告诉你他有多少个后续节点,只要利用一点点数学知识。

因为每个后续节点依次会对这个节点的右值增加2,所以后续节点的数量可以这样计算:

descendants = (right – left - 1) / 2

利用这个简单的公式,我可以立刻告诉你2-11的“Fruit”节点有4个后续节点,8-9的“Banana”节点只是1个子节点,而不是父节点。

自动化树遍历

现在你对这个表做一些事情,我们应该学习如何自动的建立表了。这是一个不错的练习,首先用一个小的树,我们也需要一个脚本来帮我们完成对节点的计数。

让我们先写一个脚本用来把一个邻接列表转换成前序遍历树表格。

<?php
function rebuild_tree($parent, $left) {
    // 这个节点的右值是左值加1
    $right = $left+1; 

    // 获得这个节点的所有子节点
    $result = mysql_query('SELECT title FROM tree '.
                           'WHERE parent="'.$parent.'";');
    while ($row = mysql_fetch_array($result)) {
        // 对当前节点的每个子节点递归执行这个函数
        // $right 是当前的右值,它会被rebuild_tree函数增加
        $right = rebuild_tree($row['title'], $right);
    } 

    // 我们得到了左值,同时现在我们已经处理这个节点我们知道右值的子节点
    mysql_query('UPDATE tree SET lft='.$left.', rgt='.
                 $right.' WHERE title="'.$parent.'";'); 

    // 返回该节点的右值+1
    return $right+1;
}
?>

这是一个递归函数。你要从rebuild_tree('Food',1); 开始,这个函数就会获取所有的“Food”节点的子节点。

如果没有子节点,他就直接设置它的左值和右值。左值已经给出了,1,右值则是左值加1。如果有子节点,函数重复并且返回最后一个右值。这个右值用来作为“Food”的右值。

递归让这个函数有点复杂难于理解。然而,这个函数确实得到了同样的结果。他沿着树走,添加每一个他看见的节点。你运行了这个函数之后,你会发现左值和右值和预期的是一样的(一个快速检验的方法:根节点的右值应该是节点数量的两倍)。

添加一个节点

我们如何给这棵树添加一个节点?有两种方式:在表中保留“parent”列并且重新运行rebuild_tree()

函数——一个很简单但却不是很优雅的函数;或者你可以更新所有新节点右边的节点的左值和右值。

第一个想法比较简单。你使用邻接列表方法来更新,同时使用改进前序遍历树来查询。如果你想添加一个新的节点,你只需要把节点插入表格,并且设置好parent列。然后,你只需要重新运行rebuild_tree() 函数。这做起来很简单,但是对大的树效率不高。

第二种添加和删除节点的方法是更新新节点右边的所有节点。让我们看一下例子。我们要添加一种新的水果——“Strawberry”,作为“Red”的最后一个子节点。首先,我们要腾出一个空间。“Red”的右值要从6变成8,7-10的“Yellow”节点要变成9-12,如此类推。更新“Red”节点意味着我们要把所有左值和右值大于5的节点加上2。

我们用一下查询:

UPDATE tree SET rgt=rgt+2 WHERE rgt>5;
UPDATE tree SET lft=lft+2 WHERE lft>5;

现在我们可以添加一个新的节点“Strawberry”来填补这个新的空间。这个节点左值为6右值为7。

INSERT INTO tree SET lft=6, rgt=7, title='Strawberry';

如果我们运行display_tree() 函数,我们将发现我们新的“Strawberry”节点已经成功地插入了树中:

Food
  Fruit
    Red
      Cherry
      Strawberry
    Yellow
      Banana
  Meat
    Beef
    Pork

缺点

首先,改进前序遍历树算法看上去很难理解。它当然没有邻接列表方法简单。然而,一旦你习惯了左值和右值这两个属性,他就会变得清晰起来,你可以用这个技术来完成临街列表能完成的所有事情,同时改进前序遍历树算法更快。当然,更新树需要很多查询,要慢一点,但是取得节点却可以只用一个查询。

总结

你现在已经对两种在数据库存储树方式熟悉了吧。虽然在我这儿改进前序遍历树算法性能更好,但是也许在你特殊的情况下邻接列表方法可能表现更好一些。这个就留给你自己决定了

最后一点:就像我已经说得我部推荐你使用节点的标题来引用这个节点。你应该遵循数据库标准化的基本规则。我没有使用数字标识是因为用了之后例子就比较难读。

进一步阅读

数据库指导 Joe Celko写的更多关于SQL数据库中的树的问题:

http://searchdatabase.techtarget.com/tip/1,289483,sid13_gci537290,00.html [6]

另外两种处理层次数据的方法:

http://www.evolt.org/article/Four_ways_to_work_with_hierarchical_data/17/4047/index.html [7]

Xindice, “本地XML数据库”:

http://xml.apache.org/xindice/ [8]

递归的一个解释:

http://www.strath.ac.uk/IT/Docs/Ccourse/subsection3_9_5.html [9]

[1] http://www.sitepoint.com/glossary.php?q=C#term_28

[2] http://www.sitepoint.com/glossary.php?q=X#term_3

[3] http://www.sitepoint.com/glossary.php?q=P#term_1

[4] http://www.sitepoint.com/glossary.php?q=P#term_50

[5] http://www.sitepoint.com/glossary.php?q=%23#term_72

[6] http://searchdatabase.techtarget.com/tip/1,289483,sid13_gci537290,00.html

[7] http://www.evolt.org/article/Four_ways_to_work_with_hierarchical_data/17/4047/index.html

[8] http://xml.apache.org/xindice/

[9] http://www.strath.ac.uk/IT/Docs/Ccourse/subsection3_9_5.html

http://www.sitepoint.com/article/hierarchical-data-database/2/

http://dev.mysql.com/tech-resources/articles/hierarchical-data.html

AJAX实现无刷新新闻评论系统

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "[url=http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd]http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd[/url]">
<html xmlns="[url=http://www.w3.org/1999/xhtml]http://www.w3.org/1999/xhtml[/url]">
<head>
<meta http-equiv="Content-Type" c />
<title>评论系统</title>
<script src="main.js"></script>
<link href="main.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="pllist">正在加载评论……
<script> loadDom();setTimeout("loadDom()",10000);</script>
</div>
<div style="width:240px;font-size:12px;text-align:center">
<fieldset><legend>评论</legend>
呢称:<input name="user" type="text" style="width:180px"/><input name="newsid" value="1" type="hidden"/>
内容:<textarea name="content" style="width:180px;height:80px"></textarea>
<input name="submit" value="我要评论" type="button" />
</fieldset>
</div>
<div style="font-size:12px;" id="msg"></div>
</body>
</html>

JS代码页(核心部分) main.js
JS代码算是本系统的一个核心部分了,Ajax的体现基本全包含在这短短数十行的代码中,是连结前台与后台处理的一个桥梁,可谓是重中之重,为了更好的让大家理解整个功能,我们将分段介绍。
1、获得XmlHttp对象,创建并返回一个XmlHttp对象。

var xhr;
function getXHR() {
try {
xhr=new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xhr=new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
xhr=false;
}
}
if(!xhr&&typeof XMLHttpRequest!='undefined') {
xhr=new XMLHttpRequest();
}
return xhr;
}
function openXHR(method,url,callback) {
getXHR();
xhr.open(method,url);
xhr.onreadystatechange=function() {
if(xhr.readyState!=4)return;
callback(xhr);
}
xhr.send(null);
}
function loadXML(method,url,callback) {
getXHR();
xhr.open(method,url);
xhr.setRequestHeader("Content-Type","text/xml");
xhr.setRequestHeader("Content-Type","GBK");
xhr.onreadystatechange=function() {
if(xhr.readyState!=4) return;
callback(xhr);
}
xhr.send(null);
}

具体的调用方法:
loadXML(method,url,callback)

method: http方法,例如:POST、GET、PUT及PROPFIND
url: 请求的URL地址,可以为绝对地址也可以为相对地址
callback:自定义的返回处理函数

2.获得评论列表
此段代码的主要功能是根据服务器处理返回的信息更新前台页面的内容,主要包括显示评论列表、评论列表分页、跳转页数三个功能。
显示评论列表:getList函数

function getList(xmlDom) {
var pllist=document.getElementById("pllist"); //获得页面pllist对象,此对象用来显示评论内容
var node=xmlDom.responseXML.getElementsByTagName("pllist");//获得pllist节点集合
var tot=xmlDom.responseXML.getElementsByTagName("pl")[0].getAttribute("tot");//获得pl节点tot属性值,这里指评论的总数量
var curpage=xmlDom.responseXML.getElementsByTagName("pl")[0].getAttribute("curpage");//获得pl节点curpage属性,这里指评论列表当前所在的页数,应用于翻页
if (tot!=0) { //判断当前评论数是否为空
var cont="";
var len=node.length;//获得pllist节点集合中节点的总数量
for(var i=0;i<len;i++) {
var u=node[i].childNodes(0).text;//获得节点第一个子节点的值,这里指呢称
var d=node[i].childNodes(1).text; //获得节点第二个子节点的值,这里指时间
var co=node[i].childNodes(2).text; //获得节点第三个子节点的值,这里指内容
var idnub=node[i].childNodes(3).text; //获得节点第四个子节点的值,这里指新闻ID
cont+='<div class="u">呢称:'+u+'</div><div class="d">时间:'+d+'</div><div class="idnub" onclick="del('+idnub+')" style="cursor:hand" onmouseout="this.style.background=\'\'" onmousemove="this.style.background=\'#99cc66\'">删除</div><div class="co">内容:'+co+'</div>'; //将所获得的评论内容生成一个字符串
}
var cont1=pagecount(tot,curpage);//调用分页函数
cont+=cont1;
pllist.innerHTML=cont;//将内容呈现
} else {
pllist.innerHTML="暂无评论!";
}
}

评论列表分页:pagecount函数

function pagecount(tot,cur) {
var cont1="";
if (tot%5==0) { //默认每页五条,这个要求与服务器端保持一致
pages=parseInt(tot/5);
} else {
pages=parseInt(tot/5)+1;
}
for(var j=1;j<=pages;j++) {
if (j==cur) {
cont1+="<span>"+j+"</span> "
} else {
cont1+="<span style='cursor:hand;color:#0000ff' onmouseout='this.style.background=\"\"' onmousemove='this.style.background=\"#99cc66\"' onclick='gotopage("+j+")'>"+j+"</span> "}
}
return cont1;
}

跳转页数:gotopage函数

function gotopage(page) {
loadXML("get","pl_list.asp?page="+page,getList);
}
function loadDom() { //定时更新评论列表,初始化10秒钟
loadXML("get","pl_list.asp",getList);
setTimeout("loadDom()",10000)
}

3.删除评论

function del(idnub) {
var msg=document.getElementById("msg");
msg.innerText="正在删除……";
loadXML("get","pl_del.asp?id="+idnub,getdel);
}
function getdel(xmlDom) { //删除后所触发的事件,更新页面
var msg=document.getElementById("msg");
msg.innerText="删除成功!";
loadXML("get","pl_list.asp",getList);
}

4.提交评论

function fb() { //处理提交
var msg=document.getElementById("msg");
var user=document.getElementById("user");
var content=document.getElementById("content")
var newsid=document.getElementById("newsid")
if (user.value=="") {
alert("呢称不可为空!");
return false;
}
if (content.value=="") {
alert("内容不可为空!");
return false;
}
msg.innerText="正在发表评论";
loadXML("get","pl_fb.asp?user="+user.value+"&content="+content.value+"&newsid="+newsid.value,getfb);
}
function getfb(xmlDom) { //评论提交后所触发的事件,更新评论列表
var msg=document.getElementById("msg");
msg.innerText=xmlDom.responseText;
loadXML("get","pl_list.asp",getList);
}

标签: 节点, AJAX, msg, var

document.createElement()的用法

 

     document.createElement()是在对象中创建一个对象,要与appendChild() 或 insertBefore()方法联合使用。其中,appendChild() 方法在节点的子节点列表末添加新的子节点。insertBefore() 方法在节点的子节点列表任意位置插入新的节点。

       下面,举例说明document.createElement()的用法。<div id="board"></div>

例1:

        <script type="text/javascript">
            var board = document.getElementById("board");
            var e = document.createElement("input");
            e.type = "button";
            e.value = "这是测试加载的小例子";
            var object = board.appendChild(e);
        </script>

效果:在标签board中加载一个按钮,属性值为“这是测试加载的小例子”。

       

例2:

        <script type="text/javascript">
            var board = document.getElementById("board");
            var e2 = document.createElement("select");
            e2.options[0] = new Option("加载项1", "");
            e2.options[1] = new Option("加载项2", "");
            e2.size = "2";
            var object = board.appendChild(e2);
        </script>

效果:在标签board中加载一个下拉列表框,属性值为“加载项1”和“加载项2”。

       

例3:

        <script type="text/javascript">
            var board = document.getElementById("board");           
            var e3 = document.createElement("input");
            e4.setAttribute("type", "text");
            e4.setAttribute("name", "q");
             e4.setAttribute("value", "使用setAttribute");
            e4.setAttribute("onclick", "javascript:alert('This is a test!');");           
            var object = board.appendChild(e3);
        </script>

效果:在标签board中加载一个文本框,属性值为“使用setAttribute”。 当点击这个文本框时,会弹出对话框“This is a test!”。

        根据上面例子,可以看出,可以通过加载对象的属性来设置,参数是相同的。使用e.type="text" 和 e.setAttribute("type","text")效果是一致的。

       

        下面,我们用实例来讲述一下appendChild() 方法和insertBefore() 方法的不同

         比如我们要在下面这个div中插入一个子节点P时:<div id="test"><p id="x1">Node</p><p>Node</p></div>

我们可以这样写:

<script type="text/javascript">
var oTest = document.getElementById("test");
var newNode = document.createElement("p");
newNode.innerHTML = "This is a test";
//测试从这里开始
//appendChild方法:
oTest.appendChild(newNode);
//insertBefore方法:
oTest.insertBefore(newNode,null);
</script>

      通过以上的代码,可以测试到一个新的节点被创建到了节点div下,且该节点是div最后一个节点。很明显,通过这个例子,可以知道appendChildhild和insertBefore都可以进行插入节点的操作。

   在上面的例子中有这样一句代码:oTest.insertBefore(newNode,null) ,这里insertBefore有2个参数可以设置,第一个是和appendChild相同的,第二却是它特有的。它不仅可以为null,还可以为:

<script type="text/javascript">
var oTest = document.getElementById("test");
var refChild = document.getElementById("x1");
var newNode = document.createElement("p");
newNode.innerHTML = "This is a test";
oTest.insertBefore(newNode,refChild);
</script>

效果:这个例子将在x1节点前面插入一个新的节点

又或:

<script type="text/javascript">
var oTest = document.getElementById("test");
var refChild = document.getElementById("x1");
var newNode = document.createElement("p");
newNode.innerHTML = "This is a test";
oTest.insertBefore(newNode,refChild.nextSibling);
</script>

效果:这个例子将在x1节点的下一个节点前面插入一个新的节点

还可为:

<script type="text/javascript">
var oTest = document.getElementById("test");
var newNode = document.createElement("p");
newNode.innerHTML = "This is a test";
oTest.insertBefore(newNode,oTest.childNodes[0]);
</script>

  这个例子将在第一子节点前面插入一个新的节点,也可以通过改变childNodes[0,1,...]来在其它位置插入新的节点

由于可见insertBefore()方法的特性是在已有的子节点前面插入新的节点,但例一中使用insertBefore()方法也可以在子节点列表末插入新节点的。两种情况结合起来,发现insertBefore()方法插入节点,是可以在子节点列表的任意位置。

  从这几个例子中得出:

  appendChild() 方法在节点的子节点列表末添加新的子节点。

  insertBefore() 方法在节点的子节点列表任意位置插入新的节点。