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 相关文章推荐
fix-ie5.js扩展在IE5下不能使用的几个方法
Aug 20 Javascript
javawscript 三级菜单的实现原理
Jul 01 Javascript
js查错流程归纳
May 04 Javascript
javascript 实现键盘上下左右功能的小例子
Sep 15 Javascript
javascript数据结构之双链表插入排序实例详解
Nov 25 Javascript
Linux下为Node.js程序配置MySQL或Oracle数据库的方法
Mar 19 Javascript
javascript解决小数的加减乘除精度丢失的方案
May 31 Javascript
jQuery Validate 数组 全部验证问题
Jan 12 Javascript
关于iframe跨域POST提交的方法示例
Jan 15 Javascript
小程序实现五星点评效果
Nov 03 Javascript
详解Node.js使用token进行认证的简单示例
May 25 Javascript
Electron+vue从零开始打造一个本地播放器的方法示例
Oct 27 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
解决163/sohu/sina不能够收到PHP MAIL函数发出邮件的问题
2009/03/13 PHP
php 获取今日、昨日、上周、本月的起始时间戳和结束时间戳的方法
2013/09/28 PHP
PHP实现数字补零功能的2个函数介绍
2014/05/12 PHP
PHP防止注入攻击实例分析
2014/11/03 PHP
PHP自定义错误处理的方法分析
2018/12/19 PHP
java script编程起步(第三课)
2007/01/10 Javascript
广泛收集的jQuery拖放插件集合
2012/04/09 Javascript
jQuery 回车事件enter使用示例
2014/02/18 Javascript
用jQuery实现的智能隐藏、滑动效果的返回顶部代码
2014/03/18 Javascript
html5+javascript制作简易画板附图
2014/04/25 Javascript
js实现文章文字大小字号功能完整实例
2014/11/01 Javascript
jQuery实现的经典滑动门效果
2015/09/22 Javascript
js获取iframe中的window对象的实现方法
2016/05/20 Javascript
jQuery移动端图片上传组件
2016/06/12 Javascript
Angular2 父子组件数据通信实例
2017/06/22 Javascript
js阻止默认右键的下拉菜单方法
2018/01/02 Javascript
浅谈layui 绑定form submit提交表单的注意事项
2019/10/25 Javascript
vue中axios防止多次触发终止多次请求的示例代码(防抖)
2020/02/16 Javascript
记一次用ts+vuecli4重构项目的实现
2020/05/21 Javascript
[02:53]DOTA2亚洲邀请赛 NewBee战队巡礼
2015/02/03 DOTA
Python实现的数据结构与算法之双端队列详解
2015/04/22 Python
Python selenium使用autoIT上传附件过程详解
2020/05/26 Python
pytorch VGG11识别cifar10数据集(训练+预测单张输入图片操作)
2020/06/24 Python
python连接mysql有哪些方法
2020/06/24 Python
Farnell德国:电子元器件供应商
2018/07/10 全球购物
欧缇丽加拿大官方网站:Caudalie加拿大
2019/07/18 全球购物
YSL圣罗兰美妆俄罗斯官网:Yves Saint Lauret RU
2020/09/23 全球购物
在C语言中实现抽象数据类型什么方法最好
2014/06/26 面试题
店长助理岗位职责
2013/12/13 职场文书
cf战队收人广告词
2014/03/14 职场文书
公开承诺书格式
2014/05/21 职场文书
代收款委托书范本
2014/10/01 职场文书
idea编译器vue缩进报错问题场景分析
2021/07/04 Vue.js
使用SQL实现车流量的计算的示例代码
2022/02/28 SQL Server
python开发制作好看的时钟效果
2022/05/02 Python