javascript代码实例教程-JS魔法堂:那些困扰你的DOM集合类型

发布时间:2019-01-29 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了javascript代码实例教程-JS魔法堂:那些困扰你的DOM集合类型脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
小宝典致力于为广大程序猿(媛)提供高品质的代码服务,请大家多多光顾小站,小宝典在此谢过。 一、前言                                  

 

  大家先看看下面的js,猜猜结果会怎样吧!

 

  可选答案:

 

  ①. 获取id属性值为id的节点元素

 

  ②. 抛namedITem is undefined的异常

 

VAR nodes = document.getElementsByName('dummyName');

var node = nodes.namedItem('id');

  答案是两种都有可能哦!document.getElementsByName在Chrome和FF30.0中返回nodelist(木有namedItem方法的),在IE全系列中都返回HTMLCollection,吐血了吧?

 

  DOM集合又何止这些呢,下面我们就一起来探讨一下吧!

 

 

 

二、困扰你我的NodeList与HTMLCollection              

 

  相同点:

 

    1. 类数组。有length属性,可以用下标索引来访问其中的元素,但没有Arrayslice等方法;

 

    2. 只读。无法增删其中的元素;

 

    3. 实时同步DOM树的变化。若DOM树有新元素加入,该类型的对象也会将新元素包含进来;

 

    4. 可通过下标数字类型索引获取集合中指定位置的元素;

 

    5. 可通过item({String | Number} 索引)方法获取集合中指定位置的元素,若通过索引找不到元素,则以第一个元素作为返回值。

 

  不同点(主要表现在HTMLCollection比NodeList能力更强大):

 

    1. HTMLCollection对象可通过namedItem({String} id或name)获取首个匹配的元素,若没有则返回null;

 

    2. HTMLCollection对象可通过点方式获取第个id或name匹配的元素,若没有则返回undefined。

 

  各浏览器选择器返回类型差别:

 

复制代码

// IE678 返回具有HTMLCollection特征(有namedItem方法)的[object Object]对象

// IE9、10、11、FF、Chrome均返回HTMLCollection

document.images;

document.links;

document.anchors;

document.forms;

document.embeds;

document.scripts;

document.applets;

document.plugins;

Node对象.getelementsbytagname;

Node对象.getElementsByTagNameNS;

Node对象.getElementsByClassName;

HTMLTableElement对象.tBodies;

HTMLTableElement对象.children;

HTMLTableElement对象.rows;

HTMLTableRowElement对象.cells;

HTMLMapElement对象.areas;

 

 

// IE678 返回具有HTMLCollection特征(有namedItem方法)的[object Object]对象

// IE9、10、11返回HTMLCollection

// FF30.0、Chrome返回NodeList

document.getElementsByName;

 

// IE678 返回具有NodeList特征(无namedItem方法)的[object Object]对象

// IE9、10、11、FF、Chrome均返回NodeList

Node对象.childNodes;

 

// IE5678 返回具有HTMLCollection特征(有namedItem方法)的[object Object]对象

// IE9、10返回[object HTMLCollection]

// IE11、Chrome返回[object HTMLAllCollection]

// FF30.0返回[object HTML document.all class]

document.all;

复制代码

 1. 总体来说Chrome的实现更接近W3C规范;

 

 2. HTMLAllCollection、HTMLCollection和[object HTML document.all class]功能没什么区别,只是类型不同而已;

 

 3. 由于document.getElementsByName在不同的浏览器中返回不同类型的对象,因此推荐使用[{Number} 索引]的方法来访问集合元素会省心一些;

 

 4. 题外话:children属性仅获取nodeTyPE为1的元素,而childNodes会将所有子元素的包含进来;

 

 5. 注意:IE9、10、11的HTMLCollection与其他浏览器的HTMLCollection可不相同哦,具体请看下一节吧!

 

 

 

三、同名不同性——IE下怪异的HTMLCollection               

 

  假如大家看过《JS魔法堂:追忆那些原始的选择器》,应该了解到在IE5678下,document.all会返回一个类函数对象,也就是上文说到的带有HTMLCollection特征的[object Object]对象。其实IE这一传统一直延续到IE11,这就导致IE9、10、11下的HTMLCollection与W3C标准出现同名而不同性质的问题了。

 

  何为类函数?

 

纯属本人私自定义而已,用于指那些拥有函数的特征,但instanceof Function却返回false的对象。

 

     真心想对IE说一句,你这么吊,你妈妈知道吗?

 

 

 

四、staticNodeList——伪装成NodeList的小子                

 

  从IE8开始就多了个querySelectorAll选择器方法。具体行为如下:

 

复制代码

// IE8返回 [object Object], IE9+和chrome、FF就返回[object NodeList]

var nodes =  document.querySelectorAll('*');

 

// IE8返回 空集合[object Object],IE9+和chrome、FF就抛至少是1个函数入参的异常

nodes = document.querySelectorAll();

 

// 各浏览器均抛SyntaxError异常

nodes = document.querySelectorAll('') 或 document.querySelectorAll(非字符串类型入参);

复制代码

 

 

大家不要被浏览器返回的NodeList所蒙骗,其实querySelectorAll返回的是StaticNodeList对象。其特征与NodeList基本无异,唯一的区别就是StaticNodeList是不会实时同步DOM树变化,因此在Polyfill querySelectorAll的时候就不用考虑实时同步DOM树变化的问题了。 

 

 

 

五、HTMLOptionsCollection——HTMLCollection的子类            

 

  HTMLSelectElement对象.options会返回一个HTMLOptionsCollection集合对象,集合内存储HTMLOptionElement类型的元素。HTMLOptionsCollection类型除了父类HTMLCollection的特征外,还有如下成员方法、属性可用。

 

add({HTMLOptionElement} opt[, {HTMLOption | Number} before]); // 将选项元素加入到集合的最后,或指定的元素(位置)的后面

remove({Number} index);// 删除指定位置的选项

selectedIndex; // 当前选中项的索引,从0开始

 

 

六、HTMLFormControllersCollection——HTMLCollection的子类         

 

  HTMLFormElement对象.elements会返回一个HTMLFormControllersCollection集合对象,集合内存储各种表单元素。它特别之处是通过点属性获取id或name匹配的元素时,一般的HTMLCollection集合对象在即使有多个匹配的元素的情况下,仅返回首个匹配的元素;而HTMLFormControllersCollection,在有一个匹配的元素时就返回该元素,若有多个匹配的元素则返回一个RadioNodeList集合对象。

 

 

 

七、RadioNodeList——NodeList的子类                      

 

  初看RadioNodeList很有可能以为集合元素就是单选表单元素,其实RadioNodeList可以存储任意类型的表单元素。不过其value属性就值显示其中被选中的单选项表单元素的value值,若没有单选项表单元素,或没有选中单选项表单元素,那么value值为空字符串。

 

 

 

八、HTMLAllCollection——HTMLCollection的子类               

 

  IE11、Chrome开始,document.all将返回HTMLCollection子类HTMLAllCollection的对象,其行为特征和HTMLCollection一致。但IE11中的HTMLAllCollection还可以当作函数使用,具体请看本文的第三节。

 

 

 

九、NamedNodeMap——无序Attr元素集合                    

 

  HTMLElement对象.attributes会返回NamedNodeMap集合对象,内部保存的是[object Attr]类型的对象。NamedNodeMap和HTMLCollection、NodeList不同,因为它是无序集合,虽然可以通过数字类型的下标索引访问NamedNodeMap集合中的元素,但该索引值并不真实代表元素在集合中的位置。下面是NamedNodeMap的成员方法:

 

复制代码

item({Number | String} 索引)

getNamedItem(); //通过名称返回指定的属性节点

getNamedItemNS(); //通过名称和命名空间返回指定的属性节点

setNamedItem(); //通过名称设置指定的属性节点

setNamedItemNS(); //通过名称和命名空间设置指定的属性节点

removeNamedItem(); //通过名称删除指定的属性节点

removeNamedItemNS(); //通过名称和命名空间删除指定的属性节点

复制代码

  注意:HTMLElement对象.attributes仅返回显示属性(简单地说就是直接写在html标签上的属性,或通过setattribute设置的属性,具体请看《JS魔法堂:不要再被Attribute和Property困扰我们了》)

 

 

 

十、DOMTokenList——HTML5新特性classList的类型哦!        

 

  用过classList的都知道它大大提高了我们设置css类的效率,但IE10以下却不支持,polyfill可以帮我们一把。但在polyfill前,我们应该先了解清楚classList的类型DOMTokenList的特征。

 

  1. 只读

 

  2. 实时同步相应元素的classname属性值的变化

 

  3. 拥有以下方法和属性

 

复制代码

 {Undefined} add({String} class); // 已存在的类不会被重复添加

 {Undefined}  remove({String} class)

 {Undefined}  toggle({String} class)

 {Boolean} contains({String} class); //检查是否有指定的类

 item({Number} 索引); //通过索引获取指定位置的类

 length; //表示类的个数

 // 无法通过[{Number} 索引]的方式来设置类,只能通过该方式来获取类

复制代码

  那么现在我们就着手polyfill吧,注意难点在实时同步这一块,解决办法就是用OnPRopertychange来监听className的变化(想了解更多,请看《JS魔法堂:DOM世界的观察者》)

 

复制代码

function polyfillClassList(el){

  var r = //s+/, cls = el.className, _inner  =  cls ? cls.trim().split(r) : [];

  var listener = function(e){

    if (e.propertyName !== 'className') return void 0;

 

    var cLst = el.classList, oLen = _inner.length, cls=  el.className;

    _inner  =  cls ? cls.trim().split(r) : [];

    var len = (cLst.length = _inner.length);

    for (var i = 0, maxLen = Math.max(oLen, len); i < maxLen; ++i){

       if (i < len){

           cLst[i] = _inner[i])

       } else {

           delete cLst[i];

       }

    }    

  };

  el.attachEvent('onpropertychange', listener);

  el.classList = {

     length: _inner.length,

     item: function(index){

        return _inner[index] || null;

     },

     add: function(cls){

       // 省略检查cls值是否有效的代码

       if (this.contains(cls)) return void 0;

  

       el.detachEvent('onpropertychange',  listener);

       el.className += ' ' + cls;

       _inner.push(cls);

       this[this.length++] = cls;

       el.attachEvent('onpropertychage', listener);

     },

     remove: function(cls){

       // 省略检查cls值是否有效的代码

       if (!this.contains(cls)) return void 0;

 

       el.detachEvent('onpropertychange',  listener);

       el.className = el.className.replace(new RegExp('//b' + cls + '//b', 'i'), '').trim();

       _inner.splice(_inner.indexOf(cls), 1);

       --this.length;

       el.attachEvent('onpropertychage', listener);

     },

     toggle: function(cls){

       // 省略检查cls值是否有效的代码

       this[this.contains(cls) ? 'remove' : 'add'](cls);

     },

     contains: function(cls){

       // 省略检查cls值是否有效的代码

       return el.className.seArch(new RegExp('//b' + cls + '//b', 'i')) >= 0;

     },

     toString: function(){

       return _inner.toString();

     }

  };  

 

  // 初始化classList[{Number} 索引]获取Attr元素

  for (var i = 0, len = _inner.length; i < len; ++i ){

    el.classList[i] = _inner[i];

  }

}        

复制代码

由于当原生的add、remove、contains和toggle方法的入参值包含空格时,会抛出InvalIDCharacterError,因此在polyfill时也要做相应的检查和抛出异常

 

复制代码

// 模拟InvalidCharacterError类

var InvalidCharacterError =  function(msg){

   this.code = 5;

   this.message = msg;

   this.name = 'InvalidCharacterError';

};

InvalidCharacterError.prototype = DOMException;

 

 

// 检查入参并抛异常

// @param {String} methodName add、remove等方法名

// @param {String} cls css类

var check = function(methodName, cls){

  var msgTpl = ["Failed to execute '", , "' on 'DOMTokenList': The token provided ('", ,"') contains HTML space characters, which are not valid in tokens."];

  if (//s+/.test(cls)){

     throw new InvalidCharacterError((msgTpl[1] = methodName, msgTpl[3] = cls, msgTpl).join(''));

  }

};

复制代码

   更多关于异常处理、Error和Exception的信息请留意《JS魔法堂:异常处理并不那么简单》

觉得可用,就经常来吧! 脚本宝典 欢迎评论哦! js脚本,巧夺天工,精雕玉琢。小宝典献丑了!

脚本宝典总结

以上是脚本宝典为你收集整理的javascript代码实例教程-JS魔法堂:那些困扰你的DOM集合类型全部内容,希望文章能够帮你解决javascript代码实例教程-JS魔法堂:那些困扰你的DOM集合类型所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。