JavaScript核心之DOM中Node节点中的接口方法

目录

1 NodeList接口,HTMLCollection接口

1.1 NodeList接口

1.2 HTMLCollection接口

2 ParentNode接口,ChildNode接口

2.1 ParentNode接口

2.1.1 children

2.1.2 firstElementChild

2.1.3 lastElementChild

2.1.4 childElementCount

2.2 ChildNode接口

2.2.1 remove()

2.2.2 before()

2.2.3 after()

2.2.4 replaceWith()

3 html元素

3.1 clientWidth属性,clientHeight属性

3.2 offsetWidth属性,offsetHeight属性

3.3 dataset属性

3.4 tabindex属性

4 页面位置相关属性

4.1 offsetParent属性、offsetTop属性和offsetLeft属性

5 table元素


1 NodeList接口,HTMLCollection接口

节点对象都是单个节点,但是有时会需要一种数据结构,能够容纳多个节点。DOM提供两种接口,用于部署这种节点的集合:NodeList接口和HTMLCollection接口。

1.1 NodeList接口

有些属性和方法返回的是一组节点,比如Node.childNodes、document.querySelectorAll()。它们返回的都是一个部署了NodeList接口的对象。

NodeList接口有时返回一个动态集合,有时返回一个静态集合。所谓动态集合就是一个活的集合,DOM树删除或新增一个相关节点,都会立刻反映在NodeList接口之中。Node.childNodes返回的,就是一个动态集合。

var parent = document.getElementById('parent');
parent.childNodes.length // 2
parent.appendChild(document.createElement('div'));
parent.childNodes.length // 3

上面代码中,parent.childNodes返回的是一个部署了NodeList接口的对象。当parent节点新增一个子节点以后,该对象的成员个数就增加了1。

document.querySelectorAll方法返回的是一个静态,DOM内部的变化,并不会实时反映在该方法的返回结果之中。

NodeList接口提供length属性和数字索引,因此可以像数组那样,使用数字索引取出每个节点,但是它本身并不是数组,不能使用pop或push之类数组特有的方法。

// 数组的继承链
myArray --> Array.prototype --> Object.prototype --> null

// NodeList的继承链
myNodeList --> NodeList.prototype --> Object.prototype --> null

从上面的继承链可以看到,NodeList接口对象并不继承Array.prototype,因此不具有数组接口提供的方法。如果要在NodeList接口使用数组方法,可以将NodeList接口对象转为真正的数组。

var div_list = document.querySelectorAll('div');
var div_array = Array.prototype.slice.call(div_list);

也可以通过下面的方法调用。

var forEach = Array.prototype.forEach;

forEach.call(element.childNodes, function(child){
  child.parentNode.style.color = '#0F0';
});

上面代码让数组的forEach方法在NodeList接口对象上调用。

不过,遍历NodeList接口对象的首选方法,还是使用for循环。

for (var i = 0; i < myNodeList.length; ++i) {
  var item = myNodeList[i];
}

不要使用for...in循环去遍历NodeList接口对象,因为for...in循环会将非数字索引的length属性和下面要讲到的item方法,也遍历进去,而且不保证各个成员遍历的顺序。

ES6新增的for...of循环,也可以正确遍历NodeList接口对象。

var list = document.querySelectorAll( 'input[type=checkbox]' );
for (var item of list) {
  item.checked = true;
}

NodeList接口提供item方法,接受一个数字索引作为参数,返回该索引对应的成员。如果取不到成员,或者索引不合法,则返回null。

nodeItem = nodeList.item(index)

// 实例
var divs = document.getElementsByTagName("div");
var secondDiv = divs.item(1);

上面代码中,由于数字索引从零开始计数,所以取出第二个成员,要使用数字索引1。

所有类似数组的对象,都可以使用方括号运算符取出成员,所以一般情况下,都是使用下面的写法,而不使用item方法。

nodeItem = nodeList[index]

1.2 HTMLCollection接口

HTMLCollection接口与NodeList接口类似,也是节点的集合,但是集合成员都是Element节点。该接口都是动态集合,节点的变化会实时反映在集合中document.links、docuement.forms、document.images等属性,返回的都是HTMLCollection接口对象

部署了该接口的对象,具有length属性和数字索引,因此是一个类似于数组的对象。

item方法根据成员的位置参数(从0开始),返回该成员。如果取不到成员或数字索引不合法,则返回null。

var c = document.images;
var img1 = c.item(10);

// 等价于下面的写法
var img1 = c[1];

namedItem方法根据成员的ID属性或name属性,返回该成员。如果没有对应的成员,则返回null。

// HTML代码为
// <form id="myForm"></form>
var elem = document.forms.namedItem("myForm");
// 等价于下面的写法
var elem = document.forms["myForm"];

由于item方法和namedItem方法,都可以用方括号运算符代替,所以建议一律使用方括号运算符。

2 ParentNode接口,ChildNode接口

不同的节点除了继承Node接口以外,还会继承其他接口。ParentNode接口用于获取当前节点的Element子节点,ChildNode接口用于处理当前节点的子节点(包含但不限于Element子节点)

2.1 ParentNode接口

ParentNode接口用于获取Element子节点。Element节点、Document节点和DocumentFragment节点,部署了ParentNode接口。凡是这三类节点,都具有以下四个属性,用于获取Element子节点。

2.1.1 children

children属性返回一个动态的HTMLCollection集合,由当前节点的所有Element子节点组成

下面代码遍历指定节点的所有Element子节点。

if (el.children.length) {
  for (var i = 0; i < el.children.length; i++) {
    // ...
  }
}

2.1.2 firstElementChild

firstChild属性返回当前节点的第一个Element子节点,如果不存在任何Element子节点,则返回null

document.firstElementChild.nodeName
// "HTML"

上面代码中,document节点的第一个Element子节点是<HTML>。

2.1.3 lastElementChild

lastElementChild属性返回当前节点的最后一个Element子节点,如果不存在任何Element子节点,则返回null

document.lastElementChild.nodeName
// "HTML"

上面代码中,document节点的最后一个Element子节点是<HTML>。

2.1.4 childElementCount

childElementCount属性返回当前节点的所有Element子节点的数目。

2.2 ChildNode接口

ChildNode接口用于处理子节点(包含但不限于Element子节点)。Element节点、DocumentType节点和CharacterData接口,部署了ChildNode接口。凡是这三类节点(接口),都可以使用下面四个方法。但是现实的情况是,除了第一个remove方法,目前没有浏览器支持后面三个方法。

2.2.1 remove()

remove方法用于移除当前节点。

el.remove()

上面方法在DOM中移除了el节点。注意,调用这个方法的节点,是被移除的节点本身,而不是它的父节点。

2.2.2 before()

before方法用于在当前节点的前面,插入一个同级节点。如果参数是节点对象,插入DOM的就是该节点对象;如果参数是文本,插入DOM的就是参数对应的文本节点。

2.2.3 after()

after方法用于在当前节点的后面,插入一个同级节点。如果参数是节点对象,插入DOM的就是该节点对象;如果参数是文本,插入DOM的就是参数对应的文本节点。

2.2.4 replaceWith()

replaceWith方法使用参数指定的节点,替换当前节点。如果参数是节点对象,替换当前节点的就是该节点对象;如果参数是文本,替换当前节点的就是参数对应的文本节点。

3 html元素

html元素是网页的根元素,document.documentElement就指向这个元素

3.1 clientWidth属性,clientHeight属性

这两个属性返回视口(viewport)的大小,单位为像素。所谓“视口”,是指用户当前能够看见的那部分网页的大小

document.documentElement.clientWidth和document.documentElement.clientHeight,基本上与window.innerWidth和window.innerHeight同义。只有一个区别,前者不将滚动条计算在内(很显然,滚动条和工具栏会减小视口大小),而后者包括了滚动条的高度和宽度。

3.2 offsetWidth属性,offsetHeight属性

这两个属性返回html元素的宽度和高度,即网页的总宽度和总高度。

3.3 dataset属性

dataset属性用于操作HTML标签元素的data-*属性。下面是一个有data-*属性的div节点。

<div id="myDiv" data-id="myId"></div>

要读取data-id属性,可以从当前节点的dataset.id属性读取。

var id = document.getElementById("myDiv").dataset.id;

要设置data-id属性,可以直接对dataset.id赋值。如果该属性不存在,将会被新建。

document.getElementById('myDiv').dataset.id = 'hello';

删除一个data-*属性,可以直接使用delete命令。

delete document.getElementById("myDiv").dataset.id;

除了dataset属性,也可以用getAttribute('data-foo')removeAttribute('data-foo')setAttribute('data-foo')hasAttribute('data-foo')等方法操作data-*属性。

需要注意的是,dataset属性使用骆驼拼写法表示属性名,这意味着data-hello-world会用dataset.helloWorld表示。而如果此时存在一个data-helloWorld属性,该属性将无法读取,也就是说,data-*属性本身只能使用连词号,不能使用骆驼拼写法。

3.4 tabindex属性

tabindex属性用来指定,当前HTML元素节点是否被tab键遍历,以及遍历的优先级

var b1 = document.getElementById("button1");

b1.tabIndex = 1;
  • 如果 tabindex = -1 ,tab键跳过当前元素。
  • 如果 tabindex = 0 ,表示tab键将遍历当前元素。如果一个元素没有设置tabindex,默认值就是0。
  • 如果 tabindex 大于0,表示tab键优先遍历。值越大,就表示优先级越大。

4 页面位置相关属性

4.1 offsetParent属性、offsetTop属性和offsetLeft属性

这三个属性提供Element对象在页面上的位置。

  • offsetParent:当前HTML元素的最靠近的、并且CSS的position属性不等于static的父元素。
  • offsetTop:当前HTML元素左上角相对于offsetParent的垂直位移。
  • offsetLeft:当前HTML元素左上角相对于offsetParent的水平位移。

如果Element对象的父对象都没有将position属性设置为非static的值(比如absolute或relative),则offsetParent属性指向body元素。另外,计算offsetTop和offsetLeft的时候,是从边框的左上角开始计算,即Element对象的border宽度不计入offsetTop和offsetLeft。

5 table元素

表格有一些特殊的DOM操作方法。

  • insertRow():在指定位置插入一个新行(tr)。
  • deleteRow():在指定位置删除一行(tr)。
  • insertCell():在指定位置插入一个单元格(td)。
  • deleteCell():在指定位置删除一个单元格(td)。
  • createCaption():插入标题。
  • deleteCaption():删除标题。
  • createTHead():插入表头。
  • deleteTHead():删除表头。

下面是使用JavaScript生成表格的一个例子。

var table = document.createElement('table');
var tbody = document.createElement('tbody');
table.appendChild(tbody);

for (var i = 0; i <= 9; i++) {
  var rowcount = i + 1;
  tbody.insertRow(i);
  tbody.rows[i].insertCell(0);
  tbody.rows[i].insertCell(1);
  tbody.rows[i].insertCell(2);
  tbody.rows[i].cells[0].appendChild(document.createTextNode('Row ' + rowcount + ', Cell 1'));
  tbody.rows[i].cells[1].appendChild(document.createTextNode('Row ' + rowcount + ', Cell 2'));
  tbody.rows[i].cells[2].appendChild(document.createTextNode('Row ' + rowcount + ', Cell 3'));
}

table.createCaption();
table.caption.appendChild(document.createTextNode('A DOM-Generated Table'));

document.body.appendChild(table);

这些代码相当易读,其中需要注意的就是insertRow和insertCell方法,接受一个表示位置的参数(从0开始的整数)。

table元素有以下属性:

  • caption:标题。
  • tHead:表头。
  • tFoot:表尾。
  • rows:行元素对象,该属性只读。
  • rows.cells:每一行的单元格对象,该属性只读。
  • tBodies:表体,该属性只读。

猜你喜欢

转载自blog.csdn.net/u012060033/article/details/89710500