从封装函数到实现简易版自用jQuery (一)

温馨提示

本文阅读对象: 对 JavaScript 有一定的了解,如果你没有学过或者忘记 JavaScript 某些操作,请看 阮一峰 JavaScript 教程

导语

DOM 有许多 API ,但是有些 API 太难用了。
比如,想获取某 element 的所有兄弟该怎么办?
再比如,我想给某 element 加多个 class ,你说有 node.classList.add( )啊。那我想加 100 个怎么办?总不能写 100 遍吧,so 自己封装个 API 。

向大佬学习

自己写一个毫无头绪啊,那jQuery是怎么做的,我们模仿一下嘛。 在jQuery这个库里,有许多函数,比如addClass( ),.css( ),.data( )等等。也就是说,jQuery是一个大仓库,仓库里有很多工具,我们需要什么的时候就用什么工具。 现在我们要做的就是,自己生产很多工具,然后建立自己的仓库,我们想用什么就从仓库里拿出来什么。

1. 生产工具

假设我们现在需要两个工具,分别是获取兄弟 element 和 添加多个 class 。

实现功能

1. 获取兄弟 element

操作步骤:

  1. 在 html 中有一个 ul 标签,在 ul 中有 5 个 li 。
<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>
复制代码
  1. 获取 id 为 item3 的兄弟元素。
    首先定义一个 allChildren 变量来存储 item3 的父节点所有的子元素。 获取子元素 DOM 有两个 API ,node.parent.children 和 node.parent.childNodes 。应该选择哪个呢?

    parent.childNodes:获取节点,不同浏览器表现不同;

  IE:只获取元素节点;

  非IE:获取元素节点与文本节点;

  parent.children:获取元素节点,浏览器表现相同。

  因此建议使用children。   

var allChildren = item3.parentNode.children;
复制代码

上图是在某博客页面做的测试,可以看到使用 parent.childNodes 获取到了 text 节点。

  1. 定义一个空数组来存兄弟元素,此时数组长度为0。
var arr = {length:0};
复制代码
  1. 遍历所有的孩子节点,如果不是 item3 ,那么就存到 arr 数组中。
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( )等方法的。

封装成函数

  1. 包装一下,加个 function ,同时起个名字,方便调用。
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);
}
复制代码
  1. 我们给这个函数一个返回值,返回值呢就是这个数组,把 console.log(arr) 改成 return arr
  2. 此时我们发现,item3 这个 id 是函数外面的值,是在调用函数的时候传参才能获取到,所以给我们的函数加一个参数,同时把 item3 改成参数 node 。
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)); 
复制代码

2. 添加多个 class

操作流程同上,这里只给出代码和必要的解释。

实现功能

<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 基础。

运行结果

2. 建造仓库放工具

现在我们的工具都造好了,就要给工具造房子了。
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。

小结

到这为止,你已经学会了写一个自己的仓库。我们再来回顾一下流程吧。

生产工具:

  1. 实现功能
  2. 封装成函数
  3. 适当优化

建造仓库放工具:

  1. 建一个仓库
  2. 放入工具

快动手实现一个属于自己的仓库吧, 代码的后续优化请看 从封装函数到实现简易版自用jQuery (二)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值