JavaScript操作HTML DOM节点的基础教程


Posted in Javascript onMarch 11, 2016

因为 DOM 的存在,这使我们可以通过 JavaScript 来获取、创建、修改、或删除节点。
NOTE:下面提供的例子中的 element 均为元素节点。
获取节点

父子关系

element.parentNode
element.firstChild/element.lastChild
element.childNodes/element.children

兄弟关系

element.previousSibling/element.nextSibling
element.previousElementSibling/element.nextElementSibling

通过节点直接的关系获取节点会导致代码维护性大大降低(节点之间的关系变化会直接影响到获取节点),而通过接口则可以有效的解决此问题。

通过节点直接的关系获取节点会导致代码维护性大大降低(节点之间的关系变化会直接影响到获取节点),而通过接口则可以有效的解决此问题。

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>ELEMENT_NODE & TEXT_NODE</title>
</head>
<body>
 <ul id="ul">
 <li>First</li>
 <li>Second</li>
 <li>Third</li>
 <li>Fourth</li>
 </ul>
 <p>Hello</p>
 <script type="text/javascript">
 var ulNode = document.getElementsByTagName("ul")[0];
 console.log(ulNode.parentNode);    //<body></body>
 console.log(ulNode.previousElementSibling); //null
 console.log(ulNode.nextElementSibling);  //<p>Hello</p>
 console.log(ulNode.firstElementChild);  //<li>First</li>
 console.log(ulNode.lastElementChild);  //<li>Fourth</li>
 </script>
</body>
</html>

NTOE:细心的人会发现,在节点遍历的例子中,body、ul、li、p节点之间是没有空格的,因为如果有空格,那么空格就会被当做一个TEXT节点,从而用ulNode.previousSibling获取到得就是一个空的文本节点,而不是 <li>First</li> 节点了。即节点遍历的几个属性会得到所有的节点类型,而元素遍历只会得到相对应的元素节点。一般情况下,用得比较多得还是元素节点的遍历属性。
实现浏览器兼容版的element.children
有一些低版本的浏览器并不支持 element.children 方法,但我们可以用下面的方式来实现兼容。

<html lang>
<head>
 <meta charest="utf-8">
 <title>Compatible Children Method</title>
</head>
<body id="body">
 <div id="item">
 <div>123</div>
 <p>ppp</p>
 <h1>h1</h1>
 </div>
 <script type="text/javascript">
 function getElementChildren(e){
  if(e.children){
  return e.children;
  }else{
  /* compatible other browse */
  var i, len, children = [];
  var child = element.firstChild;
  if(child != element.lastChild){
   while(child != null){
   if(child.nodeType == 1){
    children.push(child);
   }
   child = child.nextSibling;
   }
  }else{
   children.push(child);
  }
  return children;
  }
 }
 /* Test method getElementChildren(e) */
 var item = document.getElementById("item");
 var children = getElementChildren(item);
 for(var i =0; i < children.length; i++){
  alert(children[i]);
 }
 </script>
</body>
</html>

NOTE:此兼容方法为初稿,还未进行兼容性测试。
接口获取元素节点

getElementById
getElementsByTagName
getElementsByClassName
querySelector
querySelectorAll

JavaScript操作HTML DOM节点的基础教程

getElementById

获取文档中指定 id 的节点对象。

var element = document.getElementById('id');
getElementsByTagName

动态的获取具有指定标签元素节点的集合(其返回值会被 DOM 的变化所影响,其值会发生变化)。此接口可直接通过元素而获取,不必直接作用于 document 之上。

// 示例
var collection = element.getElementsByTagName('tagName');

// 获取指定元素的所有节点
var allNodes = document.getElementsByTagName('*');

// 获取所有 p 元素的节点
var elements = document.getElementsByTagName('p');
// 取出第一个 p 元素
var p = elements[0];

getElementsByClassName
获取指定元素中具有指定 class 的所有节点。多个 class 可的选择可使用空格分隔,与顺序无关。
var elements = element.getElementsByClassName('className');
NOTE:IE9 及一下版本不支持 getElementsByClassName
兼容方法

function getElementsByClassName(root, className) {
 // 特性侦测
 if (root.getElementsByClassName) {
 // 优先使用 W3C 规范接口
 return root.getElementsByClassName(className);
 } else {
 // 获取所有后代节点
 var elements = root.getElementsByTagName('*');
 var result = [];
 var element = null;
 var classNameStr = null;
 var flag = null;

 className = className.split(' ');

 // 选择包含 class 的元素
 for (var i = 0, element; element = elements[i]; i++) {
  classNameStr = ' ' + element.getAttribute('class') + ' ';
  flag = true;
  for (var j = 0, name; name = className[j]; j++) {
  if (classNameStr.indexOf(' ' + name + ' ') === -1) {
   flag = false;
   break;
  }
  }
  if (flag) {
  result.push(element);
  }
 }
 return result;
 }
}

querySelector / querySelectorAll

获取一个 list (其返回结果不会被之后 DOM 的修改所影响,获取后不会再变化)符合传入的 CSS 选择器的第一个元素或全部元素。

var listElementNode = element.querySelector('selector');
var listElementsNodes = element.querySelectorAll('selector');

var sampleSingleNode = element.querySelector('#className');
var sampleAllNodes = element.querySelectorAll('#className');

NOTE: IE9 一下不支持 querySelector 与 querySelectorAll
创建节点

创建节点 -> 设置属性 -> 插入节点

var element = document.createElement('tagName');

修改节点

textContent
获取或设置节点以及其后代节点的文本内容(对于节点中的所有文本内容)。

element.textContent; // 获取
element.textContent = 'New Content';

NOTE:不支持 IE 9 及其一下版本。
innerText (不符合 W3C 规范)
获取或设置节点以及节点后代的文本内容。其作用于 textContent 几乎一致。

element.innerText;

NOTE:不符合 W3C 规范,不支持 FireFox 浏览器。
FireFox 兼容方案

if (!('innerText' in document.body)) {
 HTMLElement.prototype.__defineGetter__('innerText', function(){
 return this.textContent;
 });
 HTMLElement.prototype.__defineSetter__('innerText', function(s) {
 return this.textContent = s;
 });
}

插入节点

appendChild

在指定的元素内追加一个元素节点。

var aChild = element.appendChild(aChild);

insertBefore

在指定元素的指定节点前插入指定的元素。

var aChild = element.insertBefore(aChild, referenceChild);

删除节点

删除指定的节点的子元素节点。

var child = element.removeChild(child);

innerHTML

获取或设置指定节点之中所有的 HTML 内容。替换之前内部所有的内容并创建全新的一批节点(去除之前添加的事件和样式)。innerHTML 不检查内容,直接运行并替换原先的内容。
NOTE:只建议在创建全新的节点时使用。不可在用户可控的情况下使用。

var elementsHTML = element.innerHTML;

存在的问题+

  • 低版本 IE 存在内存泄露
  • 安全问题(用户可以在名称中运行脚本代码)

PS: appendChild() , insertBefore()插入节点需注意的问题
使用appendChild()和insertBefore()插入节点都会返回给插入的节点,

//由于这两种方法操作的都是某个节点的子节点,所以必须现取得父节点,代码中 someNode 表示父节点 
//使用appendChild()方法插入节点 
var returnedNode = someNode.appendChild(newNode); 
alert(returnedNode == newNode) //true 
 
//使用insertBefore()方法插入节点 
var returnedNode = someNode.appendChild(newNode); 
alert(returnedNode == newNode) //true

 值得注意的是,如果这两种方法插入的节点原本已经存在与文档树中,那么该节点将会被移动到新的位置,而不是被复制。

<div id="test"> 
 <div>adscasdjk</div> 
  <div id="a">adscasdjk</div> 
</div> 
<script type="text/javascript"> 
 var t = document.getElementById("test"); 
 var a = document.getElementById('a'); 
 //var tt = a.cloneNode(true); 
 t.appendChild(a); 
</script>

在这段代码中,页面输出的结果和没有Javascript时是一样的,元素并没有被复制,由于元素本来就在最后一个位置,所以就和没有操作一样。如果把id为test的元素的两个子元素点换位置,就可以在firbug中看到这两个div已经被调换了位置。
如果我们希望把id为a的元素复制一个,然后添加到文档中,那么必须使被复制的元素现脱离文档流。这样被添加复制的节点被添加到文档中之后就不会影响到文档流中原本的节点。即我们可以把复制的元素放到文档的任何地方,而不影响被复制的元素。下面使用了cloneNode()方法,实现节点的深度复制,使用这种方法复制的节点会脱离文档流。当然,我不建议使用这种方法复制具有id属性的元素。因为在文档中id值是唯一的。

<div id="test"> 
 <div>adscasdjk</div> 
  <div id="a">adscasdjk</div> 
</div> 
<script type="text/javascript"> 
 var t = document.getElementById("test"); 
 var a = document.getElementById('a'); 
 var tt = a.cloneNode(true); 
 t.appendChild(tt); 
</script>

相似的操作方法还有 removeNode(node)删除一个节点,并返回该节;replaceNode(newNode,node)替换node节点,并返回该节点。这两种方法相对来说更容易使用一些。

Javascript 相关文章推荐
jquery select(列表)的操作(取值/赋值)
Aug 06 Javascript
基于jquery的checkbox下拉框插件代码
Jun 25 Javascript
Javascript实现关联数据(Linked Data)查询及注意细节
Feb 22 Javascript
js中方法重载如何实现?以及函数的参数问题
Aug 01 Javascript
基于JSON格式数据的简单jQuery幻灯片插件(jquery-slider)
Aug 10 Javascript
Angular2 路由问题修复详解
Mar 01 Javascript
浅谈对Angular中的生命周期钩子的理解
Jul 31 Javascript
JavaScript 自定义事件之我见
Sep 25 Javascript
JavaScript数据结构与算法之队列原理与用法实例详解
Nov 22 Javascript
解决vue项目报错webpackJsonp is not defined问题
Mar 14 Javascript
js实现鼠标拖拽div左右滑动
Jan 15 Javascript
Ant-design-vue Table组件customRow属性的使用说明
Oct 28 Javascript
举例说明JavaScript中的实例对象与原型对象
Mar 11 #Javascript
JavaScript中setTimeout和setInterval函数的传参及调用
Mar 11 #Javascript
原生JavaScript制作微博发布面板效果
Mar 11 #Javascript
JavaScript获取图片像素颜色并转换为box-shadow显示
Mar 11 #Javascript
详解Angularjs中的依赖注入
Mar 11 #Javascript
详解AngularJS过滤器的使用
Mar 11 #Javascript
javascript html5 canvas实现可拖动省份的中国地图
Mar 11 #Javascript
You might like
基于PHP 面向对象之成员方法详解
2013/05/04 PHP
codeigniter数据库操作函数汇总
2014/06/12 PHP
php根据日期或时间戳获取星座信息和生肖等信息
2015/10/20 PHP
thinkPHP5.0框架事务处理操作简单示例
2018/09/07 PHP
bcastr2.0 通用的图片浏览器
2006/11/22 Javascript
js网页实时倒计时精确到秒级
2014/02/10 Javascript
jQuery自带的一些常用方法总结
2014/09/03 Javascript
JS中产生标识符方式的演变
2015/06/12 Javascript
JavaScript仿商城实现图片广告轮播实例代码
2016/02/06 Javascript
Nodejs如何复制文件
2016/03/09 NodeJs
数据结构中的各种排序方法小结(JS实现)
2016/07/23 Javascript
Vue-Router实现页面正在加载特效方法示例
2017/02/12 Javascript
vue学习笔记之vue1.0和vue2.0的区别介绍
2017/05/17 Javascript
详解Angular的8个主要构造块
2017/06/20 Javascript
React Native之TextInput组件解析示例
2017/08/22 Javascript
使用layui定义一个模块并使用的例子
2019/09/14 Javascript
如何基于JavaScript判断图片是否加载完成
2019/12/28 Javascript
vue+elementUI(el-upload)图片压缩,默认同比例压缩操作
2020/08/10 Javascript
针对Vue路由history模式下Nginx后台配置操作
2020/10/22 Javascript
vue 实现click同时传入事件对象和自定义参数
2021/01/29 Vue.js
Python单例模式实例分析
2015/01/14 Python
python实战之实现excel读取、统计、写入的示例讲解
2018/05/02 Python
Python闭包函数定义与用法分析
2018/07/20 Python
python实现简易动态时钟
2018/11/19 Python
详解python中TCP协议中的粘包问题
2019/03/22 Python
python验证码图片处理(二值化)
2019/11/01 Python
python将字符串转变成dict格式的实现
2019/11/18 Python
python列表推导式入门学习解析
2019/12/02 Python
解析python 类方法、对象方法、静态方法
2020/08/15 Python
html5中的input新属性range使用记录
2014/09/05 HTML / CSS
房地产员工找工作的自我评价
2013/11/15 职场文书
开门红主持词
2014/04/02 职场文书
促销活动总结报告
2014/04/26 职场文书
2015年教师节慰问信
2015/03/23 职场文书
工作简报怎么写
2015/07/21 职场文书
java中用float时,数字后面加f,这样是为什么你知道吗
2021/09/04 Java/Android