节点操作

[ 导语 ]  DOM 提供节点操作的方法,是因为:DOM 节点关系指针都是只读的。

通过修改myUl的父级节点来修改其节点关系,但由于parentNode属性是只读的,所以修改无效,在IE8-浏览器下甚至会报错。

<div id="myDiv"></div>
<ul id="myUl">
    <li id="myli"></li>
</ul>
<script>
   console.log(myUl.parentNode);  // <body>
   myUl.parentNode = myDiv;
   // 标准浏览器下,依然返回<body>;而IE8-浏览器则会报错
   console.log(myUl.parentNode);
</script>

获取页面元素

为什么要获取页面元素?

例如,我们想要操作页面上的某部分(显示/隐藏),需要先获取到该部分对应的元素,才能进行后续操作。


DOM获取节点通常有以下两种方式:

1. 通过节点关系获取节点        // 缺点:可维护性差(一旦节点位置发生变化,就会影响到通过关系获取节点)

2. 通过接口获取节点,主要有以下几个方法:


[1] element = document.getElementById(id)?↓             根据 id 获取元素

element 是一个 Element 对象,如果当前文档中拥有特定 ID 的元素;不存在,则返回null。

// only document / sole

   var hello = document.getElementById("hello");

[2] collection = element.getElementsByTagName(tagName)?↓             根据标签名获取元素

该方法接收一个参数,即要取得元素的标签名,返回包含0或多个元素的类数组对象HTMLCollection。

// collection is live

   <div id="users">
	   <h2>8882人在学习该课程:</h2>
	   <ul>                                                         [
		   <li class="user">Satoshi</li>                              li.user
		   <li class="user">春来草青</li>                               li.user
		   <li class="user last">Kash</li>                            li.user.last
	   </ul>                                                        ]
   </div>

   users.getElementsByTagName("li")
   users.getElementsByTagName("li")[2]     // li.user.last
   users.getElementsByTagName("*")      // 获取所有后代元素

[3]collection =element.getElementsByClassName(className)?↓

users.getElementsByClassName("user")
users.getElementsByClassName("user")[2]       // li.user.last
users.getElementsByClassName("user last")     // li.user.last

// 兼容性问题:IE8-浏览器不支持

[4] list = element.querySelector/All(selector)?↓               根据选择器来获取元素

// list不是动态的,一旦获取就不会变化

   var users = document.querySelector("#users");     // div#users
   users = querySelectorAll(".user"); 	             // [li.user,li.user,li.user.last]
   document.querySelectorAll("#users .user");        // 同上

// 兼容性问题:所有移动端浏览器都支持;PC端,IE8+支持

元素的内容?↓

[1] innerHTML & innerText:用于获取开始标签和结束标签之间的内容。区别在于:

  • innerHTML:获取内容的时候,如果内容内容中有标签,也会把标签获取到(原封不动把内容获取到);
  • innerText:获取内容的时候,如果内容中有标签,会把标签过滤掉(会把前后的换行和空白都去掉);
   <div id="box">
		 我是一个div
		 <span>这是一个span</span>
	</div>
	<script>
		var box = document.getElementById('box');

		console.log(box.innerHTML);		/* 我是一个div
										      <span>这是一个span</span> */
		console.log(box.innerText);		// 我是一个div 这是一个span
	</script>

// innerHTML是万能的,但存在覆盖之前的事件状态、内存泄漏、安全等问题,建议仅用于创建新的节点。

[ 设置标签之间的内容 ]

box.innerHTML = '';     // 清空内容

// 通过 innerHTML 设置内容,如果内容中有标签,会以HTML的方式进行解析
    box.innerHTML = '<b>测试</b>内容';  

// 通过 innerText 设置内容,如果内容中有标签,会把标签在网页上显示出来(纯文本 - 转义字符原理)
    box.innerText = '<b>测试</b>内容';

[2] innerText & textContent:用于获取内部文本,其主要区别在于浏览器的兼容问题。

  • 谷歌:两个都支持
  • 新版的FF:两个都支持
  • 旧版的FF:只支持 textContent
  • 新版的IE(IE9+):两个都支持
  • 旧版的IE:只支持 innerText

var box = document.getElementById('box');
console.log(getInnerText(box));

// 处理innerText的兼容性问题
function getInnerText(element){
	// 判断当前浏览器是否支持元素的innerText属性。支持,则使用element.innerText获取内容,不支持,则使用element.textContent获取内容
	if(typeof element.innerText === 'string'){
		return element.innerText;
	}else{
		return element.textContent;
	}
}

动态创建元素

[1] 创建节点?!               element = document.creatElement(tagName)

// 创建指定标签名称的元素
   var li = document.creatElement("li");

[2] 插入节点?!

  • 在指定元素后面追加子节点     var achild = element.appendChild(achild);
<div id="users">
	<h2>8882人在学习该课程:</h2>
	<ul></ul>
</div>

var h2 = document.creatElement('h2');
h2.innerTest = "8882人在学习该课程:";
var ul = document.creatElement('ul');
users.appendChild(h2);
users.addpendChild(ul);
  • 在指定元素的指定子节点前面添加节点   var achild = element.insertBefore(achild,referenceChild);
<div id="users">
    <h2>8882人在学习该课程:</h2>
    <ul></ul>
</div>

var h2 = doucment.creatElement("h2");
h2.innerText = "8882人在学习该课程:";
var ul = document.creatElement('ul');
users.appendChild(ul);
users.insertBefore(h2,ul);

[3] 删除节点?!        child = element.removeChild(child)

var user2 = users.getElementsByClassName("users")[1];
user2.parentNode.removeChild(user2);

[4] 其他常用元素操作的方法

  • 替换节点    oldChild.parentNode.replaceChild(newChild, oldChild);
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<button id="btn1">新增节点替换(4替换2)</button>
<button id="btn2">原有节点替换(3替换1)</button>
<script>
    btn2.onclick = function(){
        document.body.replaceChild(div3,div1);
    }
    btn1.onclick = function(){
        var div4 = document.createElement('div');
        div4.innerHTML = '4';
        document.body.replaceChild(div4,div2);
    }
</script>
  • 复制节点       list = element.cloneNode( true | false )    boolean值,表示是否执行深复制

cloneNode()不会复制添加到DOM节点中的JS属性,如事件处理等;只复制特性和子节点,其他一切都不会复制。

<ul id="list">
    <li>1</li>
    <li>2</li>
    <li>3</li>        
</ul>
<script>
  var oList = document.getElementById('list');
  oList.index = 0;

  var deepList = oList.cloneNode(true);
  // 成功复制子节点
  console.log(deepList.children.length);// 3
  // 但并没有复制属性
  console.log(deepList.index);//undefined
  var shallowList = oList.cloneNode();
  // 浅复制不复制子节点(复制节点本身)
  console.log(shallowList.children.length);// 0
</script>