HTML5 DOM元素類名相關操做API classList簡介(轉載自張鑫旭大神)

1、其實事情的發展就像切水果

若是咱們把元素的類名操做比做「切水果」遊戲的話,其中一個單獨的類名就比如「水果」或「炸彈」!android

DOM Level 2時代,類名的獲取與設置,多半使用className屬性,className的生效近似切水果的「一刀切」。在web的初期,交互什麼的其實很簡單的來;就像切水果剛開始的時候,一次就一個水果飛上來,一刀「咔嚓」切了就好,就像使用className賦個類名值,就算偶爾冒出2個水果,className也能夠一刀切搞定的。ios

可是,隨着web的發展,交互的逐漸複雜,一次出現的水果愈來愈多,已經不是className一刀就能夠搞定的了;並且,還有炸彈,className一刀切可能就自尋死路了。web

爲了應對這種需求,顯然HTML5要作點什麼,因而classList API出現了,能夠有針對性地切水果,不會碰到炸彈什麼的……數組

這就是事情從className發展到classList的原因與過程。瀏覽器

classList雖改進,可是,從效果上講,仍是敵不過jQuery等外掛,後面會提到。app

2、瀏覽器們,大家怎麼看?

classList實際上已經出現好多年了,所以,天然,FireFox瀏覽器,Chrome瀏覽器都支持的很。IE家族中,從IE10瀏覽器開始纔開始承認classList能進能退的非一刀切作法。框架

手機上,Android 3.0+以上纔開始支持,哦,該死,這很糟糕。如今手機web app要求android 2.*也要支持。dom

截止今日,兼容性見下截圖:函數

因而可知,在PC上,若是要判斷是不是IE10+以及其餘現代瀏覽器,能夠試試:document.body.classList是否爲undefined學習

3、classList API概要

假設有這麼個空白頁面:

<body class="a b c"></body>

在Firebug以及Chrome控制檯中,運行:

document.body.classList

返回的分別是:

可見其直接暴露的API有:

  • length 屬性,表示元素類名的個數,只讀
  • item() 支持一個參數,爲類名的索引,返回對應的類名,例如上例:
    document.body.classList.item(0);

    結果是:"a".

    若是索引超出範圍,例如:

    document.body.classList.item(3);

    結果是:null.

  • add() 支持一個類名字符串參數。表示往類名列表中新增一個類名;若是以前類名存在,則添加忽略。例如:
    document.body.classList.add("c");
    document.body.classList.length    // 3

    此函數方法執行的返回值是undefined, 所以,classListadd()方法是沒法級聯的。下面的remove()方法也是如此。

  • remove() 支持一個類名字符串參數。表示往類名列表中移除該類名。例如:
    document.body.classList.remove("c");
    document.body.classList.length    // 2

    有點對應於jQuery中的removeClass()方法,而後者返回包裝器對象自己,可級聯;這裏的remove()方法返回undefined.

  • toggle() 支持一個類名字符串參數。無則加勉,有則移除之意。若類名列表中有此類名,移除之,並返回false; 若是沒有,則添加該類名,並返回true.

    更新於當日
    部分現代瀏覽器,例如Chrome瀏覽器以及Firefox 24的toggle()方法已經支持第2個參數,.toggle(token, switch). 其中參數switch爲Boolean類型值,若是爲true表示添加,若是爲false則表示移除。並返回該Boolean值。

  • contains() 支持一個類名字符串參數。表示往類名列表中是否包含該類名。有點對應jQuery中的hasClass方法,注意,這裏的是contains而不是contain,後面有個s哦!

    返回值很易懂的。若是包含,則返回true, 不包含,則false. 例如:

    document.body.classList.contains("c");    // false 由於"c"上面remove掉了

在Firebug控制檯結果中,咱們還看到了toString()方法。實際上,Chrome瀏覽器也有(未直接顯示),IE10也有,不過,彷佛來自層級更高對象的繼承。從下面截圖中的屬性顏色區分可見一斑:

就做用上講,等同於className. 例如:

document.body.classList.toString() === document.body.className; // true

4、classList的本質-DOMTokenList

classList的返回值顯示,其本質上是DOMTokenList – DOM標記列表.

DOMTokenList這種類型表示一組空間分隔的標記。一般由HTMLElement.classListHTMLLinkElement.relList,HTMLAnchorElement.relListHTMLAreaElement.relList返回。從0開始的類JavaScript數組索引。DOMTokenList始終是區分大小寫的。

在FireFox以及Chrome下,咱們執行typeof DOMTokenList的結果是:"function"; 可是在IE10下,倒是:"object".

同時雖然typeof結果爲"function",可是執行DOMTokenList()會報」Illegal constructor」錯誤;IE10執行DOMTokenList()也會報錯,錯誤是」缺乏函數」。

所以,試圖經過typeof obj == "function"來判斷obj就是個函數的作法是不徹底正確的。

5、classList的侷限

classList除了上面提到的不能級聯這個無關痛癢的侷限外,還有個比較頭疼的侷限,就是不能一次addremovetoggle多個類名。//zxx: 級聯指的是$().a().b().c()這種能夠連在一塊兒調用方法的寫法。

例如:

document.body.classList.add("c d");    // Error: String contains an invalid character
document.body.classList.add("c\x20d");   // Error: String contains an invalid character
document.body.classList.remove("c d");    // Error: String contains an invalid character

咱們要想多類名處理,須要一個一個來,例如:

var clList = document.body.classList;
clList.add("d");
clList.add("e");
clList.toString(); // "a b c d e"

多個類名添加的處理 張鑫旭-鑫空間-鑫生活

這一點來看,原生的classList API要比jQuery或MooTools等框架的addClass/removeClass/...等類名相關外掛方法弱爆了。然而,classList API沒有戀愛經歷、很是單純。所以,雖然胸小了一點;可是,富豪就是喜歡之。

6、classList的擴展

add的參數個數限制等方法比如生孩子,一次只能生一個,這符合國家要求符合規範。可是,有些有錢人,就像張藝謀,就愁孩子少,恨不能一次生他3個,咋辦呢?咱們能夠試試對classList作擴展,例如擴展一個adds方法,能夠一次添加多個類名,多個類名以空格分隔:

DOMTokenList.prototype.adds = function(tokens) {
   tokens.split(" ").forEach(function(token) {
       this.add(token);
   }.bind(this));
   return this;
};

// 看看能不能一會兒生3個孩子
var clList = document.body.classList;
clList.adds("child1 child2 child3").toString(); // "a b c child1 child2 child3"

DOMTokenList方法擴展-多類名添加示意

這樣,只要肚子夠大,想生幾個就能夠生幾個了,中國足球說不定就有但願了——11胞胎爭霸全球!

其餘些方法,您能夠作相似擴展。

可是,平心而論,單類名一個一個添加雖然苦逼了點,可是,我的情感上,由於原汁原味,更喜歡!

//zxx: ios4彷佛並未支持bind方法,所以,上面的擴展若是在手機上使用,需稍做調整。

7、結語

隨着JS API的愈來愈豐富,以及愈來愈多在現代瀏覽器、尤爲手機上的一些折騰,讓我愈來愈疑惑一些龐大框架的存在乎義。

有人可能會提出:原生的API方法名太長了,例如:addEventListenergetComputedStyleinsertAdjacentHTML,getBoundingClientRect等。

我:「而後呢……」
「名字長,很差記啊……」
我:「沒錯,而後呢……」
「文件大啊……」
我:「保留,而後呢……」
「新人很差上手啊……」
我:「算是,而後呢……」
「……」
我:「沒話說了吧,那我來講!」

1. 關於「名字長,很差記」
你父母手機號是?啊,不知道啊!那確實名字太長,不太好記。

2. 關於「文件大啊」
小明工做40年,交的養老保險金有100萬,0存款,每月能夠拿4000, 每個月結餘2000; 大明工做40年,養老保險一分錢沒交,存了100萬,每個月結餘-3000。結果,小明笑大明每月的開銷比他多1000塊,說你沒交養老保險虧大了。

dom.addEventListener$(dom).bind哪一個字符多,顯然前者,小明你贏了!

那下面代碼呢?

var addEventListener = "addEventListener";
dom[addEventListener]

var bind = "bind";
$(dom)[bind]

小明,你又贏了!JS壓縮以後呢?

var a= "addEventListener";
dom[a]

var b= "bind";
$(dom)[b]

小明,你又贏了!那多調用幾回呢?

var a= "addEventListener";
dom[a]
dom[a]
dom[a]
dom[a]
dom[a]

var b= "bind";
$(dom)[b]
$(dom)[b]
$(dom)[b]
$(dom)[b]
$(dom)[b]

同樣多,小明,你還沒輸!好吧,我再次認爲你是對的。

3. 關於「新人很差上手」
林遠圖封裝了《葵花寶典》,美名曰「辟邪劍法」,比較好上手,結果呢,其兒孫泛泛。卻是林平之,學習了盜版原生的《葵花寶典》,雖然很差上手(要咬抹布揮刀那個),可是,結果秒了餘滄海,也算高手之列了。

啊?原來你是招新人來打雜的,sorry, 網上的框架、插件確實比較適合大家。

zepto.js算是蠻簡潔的移動框架了,實際上,zepto.js有借鑑jqmobi.js(以前被intel收購,更名爲appframework)的嫌疑(糾正:zepto.js是被jqmobi.js借鑑),然後者彷佛更小,我看了下,gzip後6.7K, 小於前者9.7k(因含touch相關事件重寫). 可是,我我的看來,仍是太大了,尤爲那些DOM相關的API,都統統會孃家去吧,gzip後2~3K足矣。

天氣很熱,想釣魚了!

轉載自張鑫旭-鑫空間-鑫生活[http://www.zhangxinxu.com]

相關文章
相關標籤/搜索