js温故而知新9(操纵DOM)——进修廖雪峰的js教程

1.操纵DOM

操纵一个DOM节点现实上就是这么几个操纵:更新、遍历、增加、删除。

由于ID在HTML文档中是唯一的,所以document.getElementById()能够直接定位唯一的一个DOM节点。document.getElementsByTagName()和document.getElementsByClassName()老是返回一组DOM节点。要精确地挑选DOM,能够先定位父节点,再从父节点最先挑选,以减少局限。

// 返回ID为'test'的节点:
var test = document.getElementById('test');

// 先定位ID为'test-table'的节点,再返回其内部一切tr节点:
var trs = document.getElementById('test-table').getElementsByTagName('tr');

// 先定位ID为'test-div'的节点,再返回其内部一切class包含red的节点:
var reds = document.getElementById('test-div').getElementsByClassName('red');

// 猎取节点test下的一切直属子节点:
var cs = test.children;

// 猎取节点test下第一个、末了一个子节点:
var first = test.firstElementChild;
var last = test.lastElementChild;

第二种要领是运用querySelector()和querySelectorAll(),须要相识selector语法,然后运用前提来猎取节点,越发轻易:

// 经由过程querySelector猎取ID为q1的节点:
var q1 = document.querySelector('#q1');

// 经由过程querySelectorAll猎取q1节点内的相符前提的一切节点:
var ps = q1.querySelectorAll('div.highlighted > p');  

注重:低版本的IE<8不支撑querySelector和querySelectorAll。IE8仅有限支撑。

严格地讲,我们这里的DOM节点是指Element,然则DOM节点现实上是Node,在HTML中,Node包含Element、Comment、CDATA_SECTION等许多种,以及根节点Document范例,然则,绝大多数时候我们只体贴Element,也就是现实掌握页面构造的Node,其他范例的Node疏忽即可。根节点Document已自动绑定为全局变量document。

## 2.更新DOM ##
能够直接修正节点的文本,要领有两种:

一种是修正innerHTML属性,这个体式格局异常壮大,不只能够修正一个DOM节点的文本内容,还能够直接经由过程HTML片断修正DOM节点内部的子树:

// 猎取<p id="p-id">...</p>
var p = document.getElementById('p-id');
// 设置文本为abc:
p.innerHTML = 'ABC'; // <p id="p-id">ABC</p>
// 设置HTML:
p.innerHTML = 'ABC <span style="color:red">RED</span> XYZ';
// <p>...</p>的内部构造已修正  

用innerHTML时要注重,是不是须要写入HTML。假如写入的字符串是经由过程收集拿到了,要注重对字符编码来防止XSS进击。

第二种是修正innerText或textContent属性,如许能够自动对字符串举行HTML编码,保证没法设置任何HTML标签:

// 猎取<p id="p-id">...</p>
var p = document.getElementById('p-id');
// 设置文本:
p.innerText = '<script>alert("Hi")</script>';
// HTML被自动编码,没法设置一个<script>节点:
// <p id="p-id">&lt;script&gt;alert("Hi")&lt;/script&gt;</p>

二者的区分在于读取属性时,innerText不返回隐蔽元素的文本,而textContent返回一切文本。别的注重IE<9不支撑textContent。

修正CSS也是常常须要的操纵。DOM节点的style属性对应一切的CSS,能够直接猎取或设置。由于CSS许可font-size如许的称号,但它并不是JavaScript有用的属性名,所以须要在JavaScript中改写为驼峰式定名fontSize:

// 猎取<p id="p-id">...</p>
var p = document.getElementById('p-id');
// 设置CSS:
p.style.color = '#ff0000';
p.style.fontSize = '20px';
p.style.paddingTop = '2em';  

3.插进去DOM

当我们获得了某个DOM节点,想在这个DOM节点内插进去新的DOM,应当如何做?

假如这个DOM节点是空的,比方,<div></div>,那末,直接运用innerHTML = ‘<span>child</span>’就能够修正DOM节点的内容,相当于“插进去”了新的DOM节点。

假如这个DOM节点不是空的,那就不能这么做,由于innerHTML会直接替换掉本来的一切子节点。

有两个方法能够插进去新的节点。一个是运用appendChild,把一个子节点增加到父节点的末了一个子节点。比方:

<!-- HTML构造 -->
<p id="js">JavaScript</p>
<div id="list">
    <p id="java">Java</p>
    <p id="python">Python</p>
    <p id="scheme">Scheme</p>
</div>

把<p id=”js”>JavaScript</p>增加到<div id=”list”>的末了一项:

var
    js = document.getElementById('js'),
    list = document.getElementById('list');
    list.appendChild(js);

如今,HTML构造变成了如许:

<!-- HTML构造 -->
<div id="list">
    <p id="java">Java</p>
    <p id="python">Python</p>
    <p id="scheme">Scheme</p>
    <p id="js">JavaScript</p>
</div>

由于我们插进去的js节点已存在于当前的文档树,因而这个节点首先会从本来的位置删除,再插进去到新的位置。

更多的时候我们会从零建立一个新的节点,然后插进去到指定位置:

var
    list = document.getElementById('list'),
    haskell = document.createElement('p');
    haskell.id = 'haskell';
    haskell.innerText = 'Haskell';
    list.appendChild(haskell);

如许我们就动态增加了一个新的节点:

<!-- HTML构造 -->
<div id="list">
    <p id="java">Java</p>
    <p id="python">Python</p>
    <p id="scheme">Scheme</p>
    <p id="haskell">Haskell</p>
</div>

动态建立一个节点然后增加到DOM树中,能够完成许多功用。举个例子,下面的代码动态建立了一个<style>节点,然后把它增加到<head>节点的末端,如许就动态地给文档增加了新的CSS定义:

var d = document.createElement('style');
d.setAttribute('type', 'text/css');
d.innerHTML = 'p { color: red }';
document.getElementsByTagName('head')[0].appendChild(d);

能够在Chrome的掌握台实行上述代码,视察页面款式的变化。

3.1 insertBefore

假如我们要把子节点插进去到指定的位置怎么办?能够运用parentElement.insertBefore(newElement, referenceElement);,子节点会插进去到referenceElement之前。

照样以上面的HTML为例,假定我们要把Haskell插进去到Python之前:

<!-- HTML构造 -->
<div id="list">
    <p id="java">Java</p>
    <p id="python">Python</p>
    <p id="scheme">Scheme</p>
</div>

能够这么写:

var
    list = document.getElementById('list'),
    ref = document.getElementById('python'),
    haskell = document.createElement('p');
    haskell.id = 'haskell';
    haskell.innerText = 'Haskell';
    list.insertBefore(haskell, ref);

新的HTML构造以下:

<!-- HTML构造 -->
<div id="list">
    <p id="java">Java</p>
    <p id="haskell">Haskell</p>
    <p id="python">Python</p>
    <p id="scheme">Scheme</p>
</div>

可见,运用insertBefore重点是要拿到一个“参考子节点”的援用。许多时候,须要轮回一个父节点的一切子节点,能够经由过程迭代children属性完成:

var
    i, c,
    list = document.getElementById('list');
for (i = 0; i < list.children.length; i++) {
    c = list.children[i]; // 拿到第i个子节点
}

4.删除DOM

要删除一个节点,首先要获得该节点自身以及它的父节点,然后,挪用父节点的removeChild把本身删掉:

// 拿到待删除节点:
var self = document.getElementById('to-be-removed');
// 拿到父节点:
var parent = self.parentElement;
// 删除:
var removed = parent.removeChild(self);
removed === self; // true

注重到删除后的节点虽然不在文档树中了,但实在它还在内存中,能够随时再次被增加到别的位置。

当你遍历一个父节点的子节点并举行删除操纵时,要注重,children属性是一个只读属性,而且它在子节点变化时会及时更新。

比方,关于以下HTML构造:

<div id="parent">
    <p>First</p>
    <p>Second</p>
</div>

当我们用以下代码删除子节点时:

var parent = document.getElementById('parent');
parent.removeChild(parent.children[0]);
parent.removeChild(parent.children[1]); // <-- 浏览器报错

浏览器报错:parent.children[1]不是一个有用的节点。缘由就在于,当<p>First</p>节点被删除后,parent.children的节点数目已从2变为了1,索引[1]已不存在了。

因而,删除多个节点时,要注重children属性时候都在变化。

    原文作者:chinawzc
    原文地址: https://segmentfault.com/a/1190000008707205
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞