四、动态集合NodeLIst-HTMLCollection等
1. NodeList
NodeList 对象是一个节点的集合,是由 Node.childNodes 和 document.querySelectorAl返回的.
属性
length: NodeList 对象中包含的节点个数.
方法
item ( idx ):返回NodeList对象中指定索引的节点,如果索引越界,则
返回null.等价的写法是nodeList[idx], 不过这种情况下越界访问将返回undefined.NodeList.prototype.forEach():
forEach方法用于遍历 NodeList 的所有成员。它接受一个回调函数作为参数,每一轮遍历就执行一次这个回调函数,用法与数组实例的forEach方法完全一致。NodeList.prototype.keys(),NodeList.prototype.values(),NodeList.prototype.entries():这三个方法都返回一个 ES6 的遍历器对象,可以通过
for...of循环遍历获取每一个成员的信息。区别在于,keys()返回键名的遍历器,values()返回键值的遍历器,entries()返回的遍历器同时包含键名和键值的信息。
1 | <div id="one"><span>1</span></div> |
1.1 Node.childNodes返回动态集合
Node.childNodes返回的NodeList 对象是个实时集合。也就是说文档中的节点树发生变化,则已经存在的 NodeList 对象也会变化。
下面的例子中,在添加一个节点后,NodeList 对象也实时的增加了:
1 | <div id="one"><span>1</span></div> |
1.2 document.querySelectorAll()返回静态集合
document.querySelectorAll()返回的NodeList 对象是个静态的。也就是说文档中节点树发生变化,已存在的NodeList 对象不会变化。
下面的例子中添加了一个节点,但是NodeList 对象没有变化:
1 | <div class="one"><span>1</span></div> |
1.3 NodeList是类数组对象
NodeList是类数组对象,不是数组,除了forEach方法,NodeList 没有这些类似数组的方法。
注意:forEach方法有的浏览器不支持(QQ浏览器老版本、IE8以前)。
JavaScript 的继承机制是基于原型的。数组元素之所以有一些数组方法(比如forEach和 map),是因为它的原型链上有这些方法,如下:
myArray --> Array.prototype --> Object.prototype --> null (想要获取一个对象的原型链,可以连续的调用 Object.getPrototypeOf,直到原型链尽头).
forEach, map这些方式其实是 Array.prototype 这个对象的方法。
和数组不一样,NodeList的原型链是这样的:
myNodeList --> NodeList.prototype --> Object.prototype --> null
NodeList的原型上除了类似数组的forEach方法之外,还有item,entries,keys和values方法。
1.4 遍历NodeList对象方法
将NodeList对象转为数组
1
2
3
4
5
6var div_list = document.querySelectorAll('div'); // 返回 NodeList
var div_array = Array.prototype.slice.call(div_list); // 将 NodeList 转换为数组
//ES6 - Array.from();
var div_array_from = Array.from(div_list); //将 NodeList 转换为数组由于IE8-浏览器将NodeList实现为一个COM对象,不能使用Array.prototype.slice()方法,必须手动枚举所有成员
直接使用Array的forEach方法
1
2
3
4
5
6
7
8var forEach = Array.prototype.forEach;
var divs = document.getElementsByTagName( 'div' );
var firstDiv = divs[ 0 ];
forEach.call(firstDiv.childNodes, function( divChild ){
divChild.parentNode.style.color = '#0F0';
});请注意,在上面的代码中,将某个宿主对象 (如
NodeList) 作为this传递给原生方法 (如 forEach) 不能保证在所有浏览器中工作,已知在一些浏览器中会失败。使用for循环
1
2
3for (var i = 0; i < myNodeList.length; ++i) {
var item = myNodeList[i]; // 调用 myNodeList.item(i) 是没有必要的
}
2. HTMLCollection
HTMLCollection 接口表示一个包含了元素(元素顺序为文档流中的顺序)的通用集合(generic collection),还提供了用来从该集合中选择元素的方法和属性。
属性
length: 只读,返回集合当中子元素的数目。
方法
item ( idx ):
根据给定的索引(从0开始),返回具体的节点。如果索引超出了范围,则返回
null。namedItem():
根据 Id 返回指定节点,或者作为备用,根据字符串所表示的
name属性来匹配。根据 name 匹配只能作为最后的依赖,并且只有当被引用的元素支持name属性时才能被匹配。如果不存在符合给定 name 的节点,则返回null。
1 | <input type="text" name="mac" id="mm"> |
HTMLCollection对象与NodeList对象类似,也是节点的集合,返回一个类数组对象。
NodeList集合主要是Node节点的集合,而HTMLCollection集合主要是Element元素节点的集合。Node节点共有12种,Element元素节点只是其中一种。
HTMLCollection集合包括getElementsByTagName()、getElementsByClassName()、getElementsByName()等方法的返回值,以及children、document.links、document.forms等元素集合
HTML DOM 中的 HTMLCollection 是即时更新的(live);当其所包含的文档结构发生改变时,它会自动更新。
1 | <div id="test"></div> |
[注意]与NodeList对象类似,要想变成真正的数组Array对象,需要使用slice()方法,在IE8-浏览器中,则必须手动枚举所有成员
3. NamedNodeMap
NamedNodeMap 接口表示属性节点 Attr 对象的集合。尽管在 NamedNodeMap 里面的对象可以像数组一样通过索引来访问,但是它和 NodeList 不一样,对象的顺序没有指定。
NamedNodeMap 对象是即时的(live),因此,如果它内部包含的对象发生改变的话,该对象会自动更新到最新的状态。
属性: 该接口没有继承任何属性。
length: 只读, 返回映射(map)中对象的数量。
方法
getNamedItem() : 返回一个给定名字对应的属性节点
setNamedItem(): 替换或添加一个属性节点到映射(map)中。
removeNamedItem(): 移除一个属性节点
item(): 返回指定索引处的属性节点,当索引超出或等于属性节点的数量时,返回
null
1 | <style type="text/css"> |
该对象也是一个动态集合:
1 | <div id="test"></div> |
4. CSSStyleDeclaration
CSSStyleDeclaration 类表示一组 CSS 样式规则。MXML 编译器在和 Flex 应用程序关联的 CSS 文件中为每个选择器自动生成一个 CSSStyleDeclaration 对象。
CSSStyleDeclaration 表示一个CSS属性键值对的集合。它被用于一些API中:
元素节点的
style属性(Element.style)Element.style返回的只是行内样式,并不是该元素的全部样式。通过样式表设置的样式,或者从父元素继承的样式,无法通过这个属性得到。
CSSStyle实例的style属性window.getComputedStyle()的返回值返回的是元素的全部样式
CSSStyleDeclaration 接口可以直接读写 CSS 的样式属性,不过,连词号需要变成骆驼拼写法。
1 | <div></div> |
上面代码中,style属性的值是一个 CSSStyleDeclaration 实例。这个对象所包含的属性与 CSS 规则一一对应,但是名字需要改写,比如background-color写成backgroundColor。改写的规则是将横杠从 CSS 属性名中去除,然后将横杠后的第一个字母大写。如果 CSS 属性名是 JavaScript 保留字,则规则名之前需要加上字符串css,比如float写成cssFloat。
注意,该对象的属性值都是字符串,设置时必须包括单位,但是不含规则结尾的分号。比如,divStyle.width不能写为100,而要写为100px。
4.1 CSSStyleDeclaration 实例属性
4.1.1 CSSStyleDeclaration.cssText
cssText属性用来读写当前规则的所有样式声明文本
删除一个元素的所有行内样式,最简单方法就是设置cssText的值为空字符串
4.1.2 CSSStyleDeclaration.length
length属性返回一个整数值,表示当前规则包含多少条样式声明。
4.1.3 CSSStyleDeclaration.parentRule
parentRule属性返回当前规则所属的那个样式块(CSSRule 实例)。如果不存在所属的样式块,该属性返回null。
该属性只读,且只在使用 CSSRule 接口时有意义。
1 | <style>.one {font-size: 60px; border: 2px solid;}</style> |
删除一个元素的所有行内样式:
1 | one.cssText = ""; // "" 此时会清空所有行内样式 |
4.2 CSSStyleDeclaration 实例方法
4.2.1 getPropertyPriority()
getPropertyPriority()方法接受 CSS 样式的属性名作为参数,返回一个字符串,表示有没有设置important优先级。如果有就返回important,否则返回空字符串。
4.2.2 getPropertyValue()
getPropertyValue()方法接受 CSS 样式属性名作为参数,返回一个字符串,表示该属性的属性值。
4.2.3 item()
item()方法接受一个整数值作为参数,返回该位置的 CSS 属性名。
4.2.4 removeProperty()
removeProperty()方法接受一个属性名作为参数,在 CSS 规则里面移除这个属性,返回这个属性原来的值。
4.2.5 setProperty()
setProperty()方法用来设置新的 CSS 属性。该方法没有返回值。
该方法可以接受三个参数:
第一个参数:属性名,该参数是必需的。
第二个参数:属性值,该参数可选。如果省略,则参数值默认为空字符串。在Google Chrome浏览器中,此参数是必需的。
第三个参数:优先级,该参数可选。如果设置,唯一的合法值是
important,表示 CSS 规则里面的!important。
4.2.6 方法使用例子
1 | <div class="one" style="margin: 10px!important; color: red;">one</div> |
5. 遍历动态集合注意事项
动态集合是个很实用的概念,但在使用循环时一定要千万小心。可能会因为忽略集合的动态性,造成死循环
1 | var divs = document.getElementsByTagName("div"); |
在上面代码中,由于divs是一个HTMLElement集合,divs.length会随着appendChild()方法,而一直增加,于是变成一个死循环
为了避免此情况,一般地,可以写为下面形式
1 | var divs = document.getElementsByTagName("div"); |
一般地,要尽量减少访问NodeList、HTMLCollection、NamedNodeMap的次数。因为每次访问它们,都会运行一次基于文档的查询。所以,可以考虑将它们的值缓存起来







