第二十课:js中如何操作元素的属性系统

本章的内容有点复杂,我将用简单的方式来介绍重要的东西,不重要的东西,这里就不讲了,讲了也毛用。

通常我们把对象的非函数成员叫做属性。对元素节点来说,其属性大题分为两大类,固有属性和自定义属性。固有属性拥有默认值,并且无法删除。自定义属性是用户随意添加的键值对。浏览器提供一组API来供人们操作自定义属性,即:setAttribute,getAttribute,removeAttribute,我们统称这组API为DOM属性系统。

DOM属性系统对属性名会进行小写处理,属性值会统一转字符串,举个例子:

div.setAttribute("xxx","1");

div.setAttribute("XxX","2");

div.setAttribute("XXx",3);

div.getAttribute("xxx");

div.getAttribute("XxX");

标准浏览器以及IE8以及以上浏览器会返回"3",因为属性名name先进行小写处理,所以第三个setAttribute会覆盖前面的属性设置,值被赋值为"3"。而取值时,也会把属性名name先进行小写处理,因此以上两个getAttribute都会返回"3"(会转换成字符串)。

但是IE6-7就很变态,第二个和第三个setAttribute不会覆盖第一个的设置,但是在取值时,也就是getAttribute时,第一个返回"1",第二个也返回"1"。本人又在IE7下去测试了一下:

var div = document.createElement("div");

div.setAttribute("xXx","1");

div.setAttribute("XXX",2);

console.log(div.getAttribute("xXx"));      //"2"

console.log(div.getAttribute("XXX"));      //"2"

简直是超级表态,对于超级变态的东西,没必要深究了,忽略IE6-7。记住上面的规则就OK了。

IE6-IE7在处理固有属性时,有时需要进行名字映射,比如:class变成className,for变成htmlFor。

元素内部撑起整个属性系统的attributes类数组属性

IE6-IE7中,attributes会包含上百个特性节点。不管你是用setAttribute定义的属性,还是以el.name = key定义的属性,还是没有定义的属性。在IE8和其他浏览器中,你只看到了寥寥可数的几个特性节点,这些被称为显式属性。

显式属性是被显式设置的属性,分两种情况:一种是写在标签内的HTML属性,一种是通过setAttribute动态设置的属性。这些属性不分固有的还是自定义的,只要设置了,都会出现在attributes中。在IE6-7中,我们可以通过特性节点的specified属性判定它是否被显式设置了。在IE8以及其他浏览器可以通过hasAttribute来判定属性是否被显式设置了。

因此有以下方法判定元素的属性是否是显示设置的属性:

var isSpecified = !!"1"[0] ? function(el, attr){  return el.hasAttribute(attr) } : function(el, attr){  var val = el.attributes[attr];  return !!val && val.specified }

在IE6-7下"1"[0]返回false,而IE8和其他浏览器返回true。

HTML5对属性也进行了分类,dataset对象装载着所有以data-开头的自定义属性。classList装载着元素的所有类名。formData装载着所有要提供到后台的数据,以表单元素name值与value值构成的不透明对象(不能通过for in进行循环遍历)。表单元素的form属性总是指向其外围的表单对象form。

如何区分固有属性与自定义属性

IE下,元素节点的attributes对象有一种名为expando的的布尔属性,可以判定它是否为自定义属性。

function isCustomAttribute(attr, elem){     //true就代表attr是elem的自定义属性

  var attrs= elem.attributes;

  return attrs[attr] && attrs[attr].expando == true;

}

但是标准浏览器没有名为expando的布尔属性。

兼容性的写法如下:

function isCustomAttribute(attr,elem){    

  elem = elem || document.createElement("div");     //有些属性只有特殊元素才会有,这时才需要传入这个元素。一般的属性,直接用div元素   

  return elem.getAttribute(attr) === null && elem[attr] === undefined;

}  

只有自定义属性,在div元素下,会返回true。如果是固有属性,在div元素下,不会全部满足条件,返回false。如果是其他特殊的属性,比如:checked,这时需要传入元素节点type为radio的input(此input没有设置checked属性,最好是一个新创建的input元素,因为如果你传入一个已经通过setAttribute(checked,null),设置的input,那么测试就会有兼容性问题了),这时也不会全部满足条件,返回false。如果是name属性,直接用div来测试,这时return也会是false,因为name是固有属性。如果你把chaojidan这个名字传进去,那么以上就会return true,表明chaojidan不是固有属性。

这里需要明白的一点就是,elem参数一般不需要,如果你设置了一个div1的chaojidan = "chaojidan",然后调用isCustomAttribute(chaojidan,div1),那么就测试不出来了。因为你已经在div1上设置了属性值chaojidan了,那么你getAttribute(chaojidan)时,就会返回"chaojidao"了。你只需要调用isCustomAttribute(chaojidan)就行了,这时返回的就是true。这个方法的第二个参数,是针对div没有的属性值来设置的。

综上所述:

进行属性判定时,必须确保元素没有设置此属性,最好是新创建的元素。

如何判定浏览器是否区分固有属性和自定义属性

jQuery中通过以下方法来判断:

el.setAttribute("className","t");

el.className !== "t"; 

如果区分固有属性和自定义属性,以上会返回true。因为如果区分的话,el.setAttribute("className","t")设置的是自定义属性className,这时通过el.className会取到元素节点的class属性,而el的class属性没有设置值是undefined,因此返回true。但是在IE6-7下,是不区分固有属性和自定义属性,因此以上el.className会取到"t",返回false。

 这里再介绍一些知识点:

大家在看源码的时候,可能会看到getAttribute(name,4)这种用法,但是getAttribute只接受一个参数的。其实接受第二个参数是IE的专有方法。

在IE下,getAttribute的第二个参数有4个预设值:0是默认情况。1属性名区分大小写。2取出源代码中的原字符串值(IE6-7对动态创建的节点无效,IE6-8对布尔属性无效)。4用户href属性,取得完整路径。这里无须知道IE几下支持,只要知道有这么一个东西就行了,看源码时,至少可以看得懂。

操作class的一些工具方法:

var getClass = function(elem){

  return elem.className.replace(/s+/," ").split(" ");       //replace方法,会把类名中多余的空字符串清除掉,然后通过split方法,把类名组装成数组返回。

}

var hasClass = function(elem,cls){

  return -1 < (" "+elem.className+" ").indexOf(" "+cls+" ");   //空格隔开,才能确保cls是独立的字符串。

}

var addClass = function(elem,cls){

  if(!hasClass(elem,cls)) elem.className + = " " + cls;

}

var removeClass = function(elem,cls){

  if(hasClass(elem,cls)){

    var reg = new RegExp('(\s|^)'+cls+'(\s|$)');  

     //此正则前半部分\s,因为是new RegExp,所以需要转义,其实\s就是s,只不过s前面的需要转义。|是或的意思,^是开始标识。后半部分$是结束标识

    elem.className = elem.className.replace(reg," ");   //之所有用此正则,因为cls可能在最前面(匹配^+cls),最后面(cls+$),最中间(s+cls+s)

  }

}

var clearClass = function(elem,cls){

  elem.className = "";

}

在HTML5中,元素添加了一个classList属性对象,这个属性对象有add,toggle,remove,contains方法来操作class属性。

数组some和every方法的区别:

array1.some(callbackfn,thisArg)接受两个参数,

callbackfn
必需。 一个接受最多三个参数的函数。 some 方法会为 array1 中的每个元素调用 callbackfn 函数,直到 callbackfn 返回 true(array1.some返回true),或直到到达数组的结尾(array1.some返回false)。
thisArg
可选。 可在 callbackfn 函数中为其引用 this 关键字的对象。 如果省略 thisArg,则 undefined 将用作 this 值。

some 方法会按升序索引顺序对每个数组元素调用 callbackfn 函数,直到 callbackfn 函数返回 true。 如果找到导致 callbackfn 返回 true 的元素,则 some 方法会立即返回 true。 如果回调不对任何元素返回 true,则 some 方法会返回 false。
不为数组中缺少的元素调用该回调函数。([1,2,"",3,4]),数组的第三项不会执行回调方法
除了数组对象之外,some 方法可由具有 length 属性且具有已按数字编制索引的属性名的任何对象使用。(arguments,jQuery对象等)

function callbackfn(value, index, array1),可使用最多三个参数来声明回调函数。

every方法跟some方法很相似,除了返回值的条件不一样:

every 方法会按升序顺序对每个数组元素调用一次 callbackfn 函数,直到 callbackfn 函数返回 false。 如果找到导致 callbackfn 返回 false 的元素,则 every 方法会立即返回 false。 否则,every 方法返回 true。

综上所述:some方法,只要数组中有一个让回调方法返回true,就返回true。every方法,数组中的每一个都让回调方法返回true,才返回true。

加油!

原文地址:https://www.cnblogs.com/chaojidan/p/4165043.html