JavaScript中对DOM节点的访问、创建、修改、删除


Posted in Javascript onNovember 16, 2015

DOM
DOM就是Document object Model的缩写。文档对象模型是把XML或HTML以树节点为表现形式的文档。用DOM方法和属性,你可以访问,修改,删除页面上任意一个元素,也是可以添加一个元素。DOM是独立于语言的API,可以被任意语言所实现,当然也包括了Javascript
看看下面的一个文本。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html> 
 <head> 
  <title>My page</title> 
 </head> 
 <body> 
  <p class="opener">first paragraph</p> 
  <p><em>second</em> paragraph</p> 
  <p id="closer">final</p> 
 </body> 
</html>

 
我们来看看第二段

<p><em>second</em> paragraph</p>

可以看到这是个p标签。它被包含在body标签中。所以说body是p的父节点,p是子节点。第一段和第三段也是body的子节点。它们都是第二段的兄弟节点。这个em标签是第二段p的子节点。因此p就是它的父节点。父子节点关系能描绘出像树一样的关系。所以叫做DOM结构树(DOM tree).
 
Core DOM 和 HTML DOM
我们已经知道DOM可以描绘出HTML和XML文档。事实上HTML文档就是XML文档,只不过更为规范些。因此作为DOM Level 1的一部分,Core DOM规范适用于所有XML文档以及HTML DOM规范扩展了Core DOM.当然HTML DOM不能适用于所有的XML文档,仅仅适用于HTML文档。让我们来看看Core DOM和HTML DOM的构造器。
 
构造器关系

JavaScript中对DOM节点的访问、创建、修改、删除

访问DOM节点
当要验证表单或者更换图片之前,我们要知道怎么样访问元素(element.)。有很多方法获取元素。
 
Document节点
通过document我们可以访问当前的文档。我们可以通过firebugs(火狐插件),来查看document的属性和方法。
 
所有的节点都有nodeType,nodeName,nodeValue的属性。我们来看看document的nodeType是什么

document.nodeType;//9

 一共有12节点类型。document是9。常用的是元素(element:1),属性(attribute:2),文本(text:3)。
节点还有名称。对于HTML标签。节点名称就是标签名称。文本节点(text)的名字是#text.文档节点(document)的名字是#document.
 
节点也有值。对于文本节点,值就是文本。document的值为null
 
documentElement
XML都会有个ROOT节点来包文档包含起来。对于HTML文档。ROOT节点就是html标签。访问root节点。可以用documentElement的属性。

document.documentElement;//<html> 
document.documentElement.nodeType;//1 
document.documentElement.nodeName;//HTML 
document.documentElement.tagName;//对于element,nodeName和tagName相同

 
 Child Nodes
为了确定是否包含子节点我们可以用如下方法

document.documentElement.hasChildNodes();//true

 HTML有两个子节点。

document.documentElement.childNodes.length;//2 
 
document.documentElement.childNodes[0];//<head> 
 
document.documentElement.childNodes[1];//<body>

  也可以通过子节点访问父节点

document.documentElement.childNodes[1].parentNode;//<html>

 我们把body的引用赋值变量

var bd = document.documentElement.childNodes[1]; 
bd.childNodes.length;//9

 让我们看看body的结构

<body> 
 <p class="opener">first paragraph</p> 
 <p><em>second</em> paragraph</p> 
 <p id="closer">final</p> 
 <!-- and that's about it --> 
</body>

  
 为什么子节点个数为9个呢。
 首先是4个P还有一个注释一共4个。
 4个节点包含了3个空白的节点。这就7个。
 第8个在body和第一个p之间的空白节点。
 第9个就是在注释与</body>之间的空白节点。
 一共9个节点。
 
属性
因为第一节点是空白节点,所以第二个节点才是第一个p标签。

bd.childNodes[1];//  <p class="opener">

可以查看它是否有属性

bd.childNodes[1].hasAttributes();//true

也可以查看attributes的个数

bd.childNodes[1].attributes.length;//1 
 
//可以用index和名字来访问属性,也可以用getAttribute方法。 
bd.childNodes[1].attributes[0].nodeName;//class 
 
bd.childNodes[1].attributes[0].nodeValue;//opener 
 
bd.childNodes[1].attributes['class'].nodeValue;//opener 
 
bd.childNodes[1].getAttribute('class');//opener

 访问标签里的内容
让我们看看第一个标签p
你可以用textContent属性来访问。要注意的是,在IE浏览器中并不存在textContent,请用innerText来替换,结果都是一样的。

bg.childNodes[1].textContent;// "first paragraph"

还有一个属性是innerHTML.这并不是DOM的规范。但是主流浏览器都支持这个属性。它返回的是HTML代码。
 

bg.childNodes[1].innerHTML;// "first paragraph"

第一段没有html代码,所以结果和textContent(IE里是innerText)是一样的。来看下第二段包含HTML代码的标签

bd.childNodes[3].innerHTML;//"<em>second</em> paragraph" 
 
bd.childNodes[3].textContent;//second paragraph

 
另一种方法可以获取文本节点,然后再取nodeValue属性,代码如下

bd.childNodes[1].childNodes.length;//1 子节点个数 
 
bd.childNodes[1].childNodes[0].nodeName;// 节点名称 #text 
 
bd.childNodes[1].childNodes[0].nodeValue;//节点值 first paragraph

 
快速访问DOM
通过childNodes,parentNode,nodeName,nodeValue以及attributes,可以访问文档任意的节点了。但是在实际运用过程中,文本节点是比较讨厌的。如果文本改变了,有可能就影响脚本了。还有如果DOM树足够的深入,那么访问起来的确有些不方便。幸好我们可以用更为方便的方法来访问节点。这些方法是

getElementsByTagName()
getElementsByName()
getElementById()

首先说下getElementsByTagName()
通过一个标签名称(tag name)来获取一个html元素的集合。例子如下

document.getElementsByTagName('p').length;//3

因为返回的是个集合,我们可以用过数组下标的形式来访问或者通过item方法。比较一下还是推荐用数组的访问方法。更简单一些。

document.getElementsByTagName('p')[0];// <p class="opener"> 
document.getElementsByTagName('p').item(0);//和上面的结果一样 
 
document.getElementsByTagName('p')[0].innerHTML;//first paragraph

 
访问元素的属性,可以用attributes集合。但是更简单的方法是直接作为一个属性来访问就行。看个例子

document.getElementsByTagName('p')[2].id;//closer

要注意的是,class属性不能正常的使用。。要用className。因为class在javascript规范中是保留字。

document.getElementsByTagName('p')[0].className;//opener

我们可以用如下方法访问页面所有元素

<span style="color: #ff0000;">document.getElementsByTagName('*').length;//9</span>

注意:在IE早期的版本不支持上述方法。可以用document.all来取代。IE7已经支持了,但是返回的是所有节点(node),而不仅仅是元素节点(element nodes)。
 
 
Siblings, Body, First, Last Child
nextSibling和previousSibling是两个比较方便访问DOM的方法。用来访问相邻的节点的。例子如下

var para = document.getElementById('closer') 
para.nextSibling;//"\n" 
para.previousSibling;//"\n" 
para.previousSibling.previousSibling;//<p> 
para.previousSibling.previousSibling.previousSibling;//"\n" 
para.previousSibling.previousSibling.nextSibling.nextSibling;// <p id="closer">

 
body 用来访问body元素的。

document.body;//<body>

firstChild 和lastChild 。firstChild是和childNodes[0]一样.lastChild和 childNodes[childNodes.length - 1]一样。
 
遍历DOM
通过以上的学习,我们可以写个函数,用来遍历DOM

function walkDOM(n) { 
 do { 
  alert(n); 
  if (n.hasChildNodes()) { 
   walkDOM(n.firstChild) 
  }   
 } while (n = n.nextSibling) 
} 
 
walkDOM(document.body);//测试

修改节点
下面来看看DOM节点的修改。
先获取要改变的节点。

var my = document.getElementById('closer');

非常容易更改这个元素的属性。我们可以更改innerHTML.

my.innerHTML = 'final';//final

因为innerHTML可以写入html,所以我们来修改html。

my.innerHTML = '<em>my</em> final';//<em>my</em> fnal

em标签已经成为dom树的一部分了。我们可以测试一下

my.firstChild;//<em> 
my.firstChild.firstChild;//my

我们也可以通过nodeValue来改变值。

my.firstChild.firstChild.nodeValue = 'your';//your

 
修改样式
大部分修改节点可能都是修改样式。元素节点有style属性用来修改样式。style的属性和css属性是一一对应的。如下代码

my.style.border = "1px solid red";

CSS属性很多都有破折号("-"),如padding-top,这在javascript中是不合法的。这样的话一定要省略波折号并把第二个词的开头字母大写,规范如下。 margin-left变为marginLeft。依此类推

my.style.fontWeight = 'bold';

我们还可以修改其他的属性,无论这些属性是否被初始化。

my.align = "right"; 
my.name = 'myname'; 
my.id = 'further'; 
my;//<p id="further" align="right" style="border: 1px solid red; font-weight: bold;">

 
创建节点

为了创建一个新的节点,可以使用createElement和createTextNode.如果新建完成,可以用appendChild()把节点添加到DOM树中。
创建一个元素P,并把设置innerHTML属性

var myp = document.createElement('p'); 
myp.innerHTML = 'yet another';

 
元素P建完成了,就可以随意修改添加属性了

myp.style.border = '2px dotted blue'

 接下来可以用appendChild把新的节点添加到DOM树中的。

document.body.appendChild(myp)

 
使用DOM的方法
用innerHTML方法的确很简单,我们可以用纯的dom方法来实现上面的功能。

  • 新建一个文本节点(yet another)
  • 新建一个段落
  • 把文本节点添加到段落中。
  • 把段落添加到body中
// 创建p 
var myp = document.createElement('p'); 
// 创建一个文本节点 
var myt = document.createTextNode('one more paragraph') 
myp.appendChild(myt); 
// 创建一个STRONG元素 
var str = document.createElement('strong'); 
str.appendChild(document.createTextNode('bold')); 
// 把STRONG元素添加到P中 
myp.appendChild(str); 
// 把P元素添加到BODY中 
document.body.appendChild(myp); 
//结果<p>one more paragraph<strong>bold</strong></p> 
 cloneNode()

另一种新建节点的方法是,我们可以用cloneNode来复制一个节点。cloneNode()可以传入一个boolean参数。如果为true就是深度复制,包括他的子节点,false,仅仅复制自己。
 
首先获取要复制的元素。

var el = document.getElementsByTagName('p')[1];//<p><em>second</em> paragraph</p>

先不用深度复制。

document.body.appendChild(el.cloneNode(false))

我们发现页面并没有变化,因为仅仅复制的是元素p。和下面的效果一样。

document.body.appendChild(document.createElement('p'));

如果用深度复制,包括p下面所有的子节点都会被复制。当然包括文本节点和EM元素。

document.body.appendChild(el.cloneNode(true))

 
insertBefore()
用appendChild,就是把元素添加到最后。而insertBefore方法可以更精确控制插入元素的位置。

elementNode.insertBefore(new_node,existing_node)

实例

document.body.insertBefore( 
 document.createTextNode('boo!'), 
 document.body.firstChild 
);

 
意思就是新建一个文本节点,把它作为body元素的第一个节点。
 
 
删除节点

要从DOM树删除一个节点,我们可以使用removeChild().我们来看看要操作的HTML

<body> 
 <p class="opener">first paragraph</p> 
 <p><em>second</em> paragraph</p> 
 <p id="closer">final</p> 
 <!-- and that's about it --> 
</body>

来看看下面代码,删除第二段

var myp = document.getElementsByTagName('p')[1]; 
var removed = document.body.removeChild(myp);

removed节点就是删除的节点。以后还可以用这删除的节点。
 
我们也可以用replaceChild()方法。这个方法是删除一个节点,并用另一个节点替代。当执行上个删除节点操作之后,结果如下

<body> 
 <p class="opener">first paragraph</p> 
 <p id="closer">final</p> 
 <!-- and that's about it --> 
</body>

 我们来看看replaceChild的使用。我们把上一个删除节点来替代第二个p

var replaced = document.body.replaceChild(removed, p);

 和removeChild返回一样。replaced就是移除的节点。现在结果为

<body> 
 <p class="opener">first paragraph</p> 
 <p><em>second</em> paragraph</p> 
 <!-- and that's about it --> 
</body>
Javascript 相关文章推荐
js压缩工具 yuicompressor 使用教程
Mar 31 Javascript
javascript 词法作用域和闭包分析说明
Aug 12 Javascript
js的.innerHTML = &quot;&quot;IE9下显示有错误的解决方法
Sep 16 Javascript
JavaScript获取当前网页标题(title)的方法
Apr 03 Javascript
JavaScript中getUTCMinutes()方法的使用详解
Jun 10 Javascript
简介可以自动完成UI的AngularJS工具angular-smarty
Jun 23 Javascript
实例代码讲解jquery easyui动态tab页
Nov 17 Javascript
jQuery判断checkbox选中状态
May 12 Javascript
jQuery封装的屏幕居中提示信息代码
Jun 08 Javascript
AngularJS中filter的使用实例详解
Aug 25 Javascript
Vue父子组建的简单通信之控制开关Switch的实现
Jun 04 Javascript
vue实现输入框的模糊查询的示例代码(节流函数的应用场景)
Sep 01 Javascript
常用javascript表单验证汇总
Jul 20 #Javascript
jquery验证邮箱格式是否正确实例讲解
Nov 16 #Javascript
跟我学习javascript的call(),apply(),bind()与回调
Nov 16 #Javascript
跟我学习javascript的函数调用和构造函数调用
Nov 16 #Javascript
12种JavaScript常用的MVC框架比较分析
Nov 16 #Javascript
跟我学习javascript的函数和函数表达式
Nov 16 #Javascript
使用JQuery FancyBox插件实现图片展示特效
Nov 16 #Javascript
You might like
php array_unique之后json_encode需要注意
2011/01/02 PHP
PHP解析目录路径的3个函数总结
2014/11/18 PHP
用js实现计算加载页面所用的时间
2010/04/02 Javascript
分享14个很酷的jQuery导航菜单插件
2011/04/25 Javascript
js中return false(阻止)的用法
2013/08/14 Javascript
JQuery中阻止事件冒泡几种方式及其区别介绍
2014/01/15 Javascript
js统计页面的来访次数实现代码
2014/05/09 Javascript
EasyUI,点击开启编辑框,并且编辑框获得焦点的方法
2015/03/01 Javascript
JS+CSS实现的简单折叠展开多级菜单效果
2015/09/12 Javascript
实例解析JS布尔对象的toString()方法和valueOf()方法
2015/10/25 Javascript
基于jQuery实现的幻灯图片切换
2016/12/02 Javascript
浅谈Javascript中的Label语句
2016/12/14 Javascript
bootstrap表格分页实例讲解
2016/12/30 Javascript
详解vue-router基本使用
2017/04/18 Javascript
nodejs实现简单的gulp打包
2017/12/21 NodeJs
vue 2.x 中axios 封装的get 和post方法
2018/02/28 Javascript
js判断输入框不能为空格或null值的实现方法
2018/03/02 Javascript
浅谈super-vuex使用体验
2018/06/25 Javascript
基于Vue实现电商SKU组合算法问题
2019/05/29 Javascript
Vue项目中ESlint规范示例代码
2019/07/04 Javascript
Vue使用lodop实现打印小结
2019/07/06 Javascript
layui 解决富文本框form表单提交为空的问题
2019/10/26 Javascript
Vue中图片Src使用变量的方法
2019/10/30 Javascript
关于javascript中的promise的用法和注意事项(推荐)
2021/01/15 Javascript
[23:18]Spirit vs Liquid Supermajor小组赛A组 BO3 第二场 6.2
2018/06/03 DOTA
[02:16]2018年度CS GO最具人气选手-完美盛典
2018/12/16 DOTA
python在多玩图片上下载妹子图的实现代码
2013/08/13 Python
Pycharm学习教程(4) Python解释器的相关配置
2017/05/03 Python
Tensorflow tf.tile()的用法实例分析
2020/05/22 Python
浅谈python量化 双均线策略(金叉死叉)
2020/06/03 Python
力学专业毕业生自荐信
2013/11/17 职场文书
80后职场人的职业生涯规划
2014/03/08 职场文书
2016年会开场白台词
2015/06/01 职场文书
陪护人员误工证明
2015/06/24 职场文书
2016大学优秀学生干部事迹材料
2016/03/01 职场文书
详解Java七大阻塞队列之SynchronousQueue
2021/09/04 Java/Android