本文閱讀對象: 對 JavaScript 有必定的瞭解,若是你沒有學過或者忘記 JavaScript 某些操做,請看 阮一峯 JavaScript 教程 。javascript
DOM 有許多 API ,可是有些 API 太難用了。
好比,想獲取某 element 的全部兄弟該怎麼辦?
再好比,我想給某 element 加多個 class ,你說有 node.classList.add( )啊。那我想加 100 個怎麼辦?總不能寫 100 遍吧,so 本身封裝個 API 。css
本身寫一個毫無頭緒啊,那jQuery是怎麼作的,咱們模仿一下嘛。 在jQuery這個庫裏,有許多函數,好比addClass( ),.css( ),.data( )等等。也就是說,jQuery是一個大倉庫,倉庫裏有不少工具,咱們須要什麼的時候就用什麼工具。 如今咱們要作的就是,本身生產不少工具,而後創建本身的倉庫,咱們想用什麼就從倉庫裏拿出來什麼。html
假設咱們如今須要兩個工具,分別是獲取兄弟 element 和 添加多個 class 。java
操做步驟:node
<ul>
<li id="item1">item1</li>
<li id="item2">item2</li>
<li id="item3">item3</li>
<li id="item4">item4</li>
<li id="item5">item5</li>
</ul>
複製代碼
獲取 id 爲 item3 的兄弟元素。
首先定義一個 allChildren 變量來存儲 item3 的父節點全部的子元素。 獲取子元素 DOM 有兩個 API ,node.parent.children 和 node.parent.childNodes 。應該選擇哪一個呢?數組
parent.childNodes:獲取節點,不一樣瀏覽器表現不一樣;瀏覽器
IE:只獲取元素節點;bash
非IE:獲取元素節點與文本節點;函數
parent.children:獲取元素節點,瀏覽器表現相同。工具
所以建議使用children。
var allChildren = item3.parentNode.children;
複製代碼
上圖是在某博客頁面作的測試,能夠看到使用 parent.childNodes 獲取到了 text 節點。
var arr = {length:0};
複製代碼
for(var i = 0;i < allChildren.length;i++){
if(allChildren[i] !== item3){
arr[arr.length] = allChildren[i];
arr.length++;
}
}
複製代碼
小技巧:使用 arr[arr.length] = allChildren[i];
使得數組下標依次存儲 item 元素。
完整代碼:
<ul>
<li id="item1">item1</li>
<li id="item2">item2</li>
<li id="item3">item3</li>
<li id="item4">item4</li>
<li id="item5">item5</li>
</ul>
var allChildren = item3.parentNode.children;
var arr = {length:0};
for(var i = 0;i < allChildren.length;i++){
if(allChildren[i] !== item3){
arr[arr.length] = allChildren[i];
arr.length++;
}
}
console.log(arr);
複製代碼
運行結果:
注意: 這個 arr 數組是一個僞數組,它的原型鏈直接指向了 Object 並無指向 Array.prototype ,只有原型鏈中指向 Array.prototype 的數組纔是真正的數組。若是原型鏈中不包含 Array.prototype 是沒有數組.push( )等方法的。
function getSiblings(){
var allChildren = item3.parentNode.children;
var arr = {length:0};
for(var i = 0;i < allChildren.length;i++){
if(allChildren[i] !== item3){
arr[arr.length] = allChildren[i];
arr.length++;
}
}
console.log(arr);
}
複製代碼
console.log(arr)
改爲 return arr
。function getSiblings(node){
var allChildren = node.parentNode.children;
var arr = {length:0};
for(var i = 0;i < allChildren.length;i++){
if(allChildren[i] !== node){
arr[arr.length] = allChildren[i];
arr.length++;
}
}
return arr;
}
console.log(getSiblings(item3));
複製代碼
操做流程同上,這裏只給出代碼和必要的解釋。
實現功能:
<ul>
<li id="item1">item1</li>
<li id="item2">item2</li>
<li id="item3">item3</li>
<li id="item4">item4</li>
<li id="item5">item5</li>
</ul>
var classes = {'a':true,'b':false,'c':true}
for(var key in classes){
var value = classes[key];
if(value){
item3.classList.add(key);
}
else{
item3.classList.remove(key);
}
}
複製代碼
利用 hash 存儲是否添加的 class ,若是爲 true ,添加給 item3 ,若是爲 false 移除該 class 。
封裝成函數:
function addClasses(node,classes){
for(var key in classes){
var value = classes[key];
if(value){
node.classList.add(key);
}
else{
node.classList.remove(key);
}
}
}
addClasses(item3,{'a':true,'b':false,'c':true});
// 傳入參數包括節點和要添加的 class
複製代碼
優化整理:
function addClasses(node,classes){
for(var key in classes){
var value = classes[key];
var methodName = value ? 'add':'remove';
node.classList[methodName](key);
}
}
addClasses(item3,{'a':true,'b':false,'c':true});
複製代碼
這裏要說明一下,咱們根據傳來的 key 值爲 true 或者 false 來決定是否添加這個 class。node.classList.add(key);
和 node.classList.remove(key);
是屬於一類代碼,區別就是調用的是 add 方法仍是 remove 方法,那麼存在優化的可能性。
定義一個 methodName 變量存儲 value 值,也就是遍歷過程當中每次的 true 或者 false。讓 node.classList[methodName](key)
每次直接調用 methodName 便可完成操做。
備註:若是你只瞭解對象 obj.add( )
這種調用,不理解關於obj[]( )
調用方法,情回顧 JavaScript 基礎。
運行結果:
如今咱們的工具都造好了,就要給工具造房子了。
jQuery 工具的房子叫 jQuery ,那咱們也取一個屬於本身的名字,好比個人叫 simpleTools 。
window.simpleTools = function(){
return{
getSiblings:function(){},
addClass:function(){}
};
};
複製代碼
window.simpleTools 是咱們的大房子,這是一個函數大房子,房子裏面如今住着 getSiblings 對象和 addClass 對象,這就比如是放工具的架子。接下來,咱們把上面封裝好的函數放在對應的架子上。
window.simpleTools = function(node){
return{
getSiblings:function(){
var allChildren = node.parentNode.children;
var arr = {length:0};
for(var i = 0;i < allChildren.length;i++){
if(allChildren[i] !== node){
arr[arr.length] = allChildren[i];
arr.length++;
}
}
return arr;
},
addClass:function(classes){
for(var key in classes){
var value = classes[key];
var methodName = value ? 'add':'remove';
node.classList[methodName](key);
}
}
};
};
複製代碼
傳給 function 的 node 就好像是咱們的倉庫小管家,一旦他被通知要工做了(有參數傳過來),那他就去告訴每個工具,作好準備隨時準備開工。
如今加幾句測試語句,看看運行結果。
var nodeTest = simpleTools(item3);
console.log(nodeTest.getSiblings());
nodeTest.addClass({'a':true,'b':false,'c':true});
複製代碼
運行結果:
很好,和以前的運行結果相同,說明咱們並無由於放到倉庫裏而產生bug。
到這爲止,你已經學會了寫一個本身的倉庫。咱們再來回顧一下流程吧。
生產工具:
建造倉庫放工具:
快動手實現一個屬於本身的倉庫吧, 代碼的後續優化請看 從封裝函數到實現簡易版自用jQuery (二)。