本文阅读对象: 对 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;
复制代码
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 (二)。