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 获取对象 基本选择与层级
May 31 Javascript
javascript 内存回收机制理解
Jan 17 Javascript
最简单的js图片切换效果实现代码
Sep 24 Javascript
js jquery数组介绍
Jul 15 Javascript
Jquery getJSON方法详细分析
Dec 26 Javascript
javascript教程之不完整的继承(js原型链)
Jan 13 Javascript
JavaScript中继承用法实例分析
May 16 Javascript
JS实现同一个网页布局滑动门和TAB选项卡实例
Sep 23 Javascript
原生JS 购物车及购物页面的cookie使用方法
Aug 21 Javascript
Vue-路由导航菜单栏的高亮设置方法
Mar 17 Javascript
使用vue2.6实现抖音【时间轮盘】屏保效果附源码
Apr 24 Javascript
在layui中使用form表单监听ajax异步验证注册的实例
Sep 03 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中strtotime函数使用方法详解
2011/11/27 PHP
php中get_headers函数的作用及用法的详细介绍
2013/04/27 PHP
PHP header()函数常用方法总结
2014/04/11 PHP
php实现当前页面点击下载文件的简单方法
2016/09/22 PHP
PHP使用PHPExcel实现批量上传到数据库的方法
2017/06/08 PHP
JS 页面自动加载函数(兼容多浏览器)
2009/05/18 Javascript
JQuery扩展插件Validate—6 radio、checkbox、select的验证
2011/09/05 Javascript
对Web开发中前端框架与前端类库的一些思考
2015/03/27 Javascript
JS实现从表格中动态删除指定行的方法
2015/03/31 Javascript
jQuery过滤HTML标签并高亮显示关键字的方法
2015/08/07 Javascript
常用的Javascript设计模式小结
2015/12/09 Javascript
Node.js配合node-http-proxy解决本地开发ajax跨域问题
2016/08/31 Javascript
AngularJS 自定义过滤器详解及实例代码
2016/09/14 Javascript
JS实现旋转木马式图片轮播效果
2017/01/18 Javascript
bootstrapValidator 重新启用提交按钮的方法
2017/02/20 Javascript
Bootstrap Table 在指定列中添加下拉框控件并获取所选值
2017/07/31 Javascript
Vue表单类的父子组件数据传递示例
2018/05/03 Javascript
解决Vue+Element ui开发中碰到的IE问题
2018/09/03 Javascript
基于JavaScript实现每日签到打卡轨迹功能
2018/11/29 Javascript
Python脚本实现代码行数统计代码分享
2015/03/10 Python
Python代码解决RenderView窗口not found问题
2016/08/28 Python
python使用matplotlib绘图时图例显示问题的解决
2017/04/27 Python
Python3爬虫学习入门教程
2018/12/11 Python
python 使用poster模块进行http方式的文件传输到服务器的方法
2019/01/15 Python
pandas中的series数据类型详解
2019/07/06 Python
Python用摘要算法生成token及检验token的示例代码
2020/12/01 Python
Python Selenium XPath根据文本内容查找元素的方法
2020/12/07 Python
详解CSS透明opacity和IE各版本透明度滤镜filter的最准确用法
2016/12/20 HTML / CSS
详解移动端Html5页面中1px边框的几种解决方法
2018/07/24 HTML / CSS
户籍证明的格式
2014/01/13 职场文书
捐款倡议书
2014/04/14 职场文书
罚款通知怎么写
2015/04/22 职场文书
小学英语教学随笔
2015/08/14 职场文书
反腐倡廉学习心得体会范文
2015/08/15 职场文书
2019年二手房买卖合同范本
2019/10/14 职场文书
用React Native制作一个简单的游戏引擎
2021/05/27 Javascript