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 相关文章推荐
javascript网页关闭时提醒效果脚本
Oct 22 Javascript
js checkbox(复选框) 使用集锦
Apr 28 Javascript
基于jQuery的判断iPad、iPhone、Android是横屏还是竖屏的代码
May 11 Javascript
js 采用delete实现继承示例代码
May 20 Javascript
JavaScript验证18位身份证号码最后一位正确性的实现代码
Aug 07 Javascript
JavaScript中匿名、命名函数的性能测试
Sep 04 Javascript
简介JavaScript中的sub()方法的使用
Jun 08 Javascript
javascript弹出窗口中增加确定取消按钮
Jun 24 Javascript
node作为中间服务层如何发送请求(发送请求的实现方法详解)
Jan 02 Javascript
vue根据进入的路由进行原路返回的方法
Sep 26 Javascript
vue的keep-alive中使用EventBus的方法
Apr 23 Javascript
Vue axios 跨域请求无法带上cookie的解决
Sep 08 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
第四节--构造函数和析构函数
2006/11/16 PHP
第4章 数据处理-php正则表达式-郑阿奇(续)
2011/07/04 PHP
php生成excel列序号代码实例
2013/12/24 PHP
php上传文件并存储到mysql数据库的方法
2015/03/16 PHP
PHP使用ajax的post方式下载excel文件简单示例
2019/08/06 PHP
解决Laravel 使用insert插入数据,字段created_at为0000的问题
2019/10/11 PHP
phpStorm2020 注册码
2020/09/17 PHP
(JS实现)MapBar中坐标的加密和解密的脚本
2007/05/16 Javascript
jQuery把表单元素变为json对象
2013/11/06 Javascript
js判断浏览器类型为ie6时不执行
2014/06/15 Javascript
深入学习jQuery Validate表单验证
2016/01/18 Javascript
javascript和jQuery实现网页实时聊天的ajax长轮询
2016/07/20 Javascript
js H5 canvas投篮小游戏
2016/08/18 Javascript
jquery select2的使用心得(推荐)
2016/12/04 Javascript
Bootstrap CSS组件之导航条(navbar)
2016/12/17 Javascript
javascript实现用户点击数量统计
2016/12/25 Javascript
微信小程序实战之登录页面制作(5)
2020/03/30 Javascript
Vue.js2.0中的变化小结
2017/10/24 Javascript
Vue三层嵌套路由的示例代码
2018/05/05 Javascript
Vue实现点击当前元素以外的地方隐藏当前元素(实现思路)
2019/12/04 Javascript
vue如何使用rem适配
2021/02/06 Vue.js
python实现html转ubb代码(html2ubb)
2014/07/03 Python
深入理解Django的自定义过滤器
2017/10/17 Python
PyTorch线性回归和逻辑回归实战示例
2018/05/22 Python
详解python配置虚拟环境
2019/04/08 Python
在Tensorflow中实现梯度下降法更新参数值
2020/01/23 Python
Python数组拼接np.concatenate实现过程
2020/04/18 Python
python开根号实例讲解
2020/08/30 Python
世界首屈一指的钓鱼用品商店:TackleDirect
2016/07/26 全球购物
SNIDEL官网:日本VIVI杂志人气少女第一品牌
2020/03/12 全球购物
机关道德讲堂实施方案
2014/03/15 职场文书
教师对学生的评语
2014/04/28 职场文书
自主招生教师推荐信
2014/05/10 职场文书
英语投诉信范文
2015/07/03 职场文书
研究生学习计划书应该怎么写?
2019/09/10 职场文书
详解SpringBoot异常处理流程及原理
2021/06/21 Java/Android