封装函数到实现简化版jQuery

栏目: jQuery · 发布时间: 5年前

内容简介:然后定义一个空数组来存兄弟元素;调用这个函数同时传参,这样我们就可以给现在我们有两个
  • 获取一个节点的所有兄弟;
  • 给一个节点添加加多个 class
  • DOMAPI 实现比较繁琐,所以自己封装 API

功能实现

1.封装函数

  • 获取兄弟 操作步骤: 在 html 中有一个 ul 标签,在 ul 中有 5li
<ul>
  <li id="item1">选项1</li>
  <li id="item2">选项2</li>
  <li id="item3">选项3</li>
  <li id="item4">选项4</li>
  <li id="item5">选项5</li>
</ul>
复制代码
  • 获取 iditem3 的兄弟元素。 首先定义一个 allChildren 变量来存储 item3 的父节点所有的子元素;
var allChildren = item3.parentNode.children;
复制代码

然后定义一个空数组来存兄弟元素;

var array = {length:0};
复制代码
  • 遍历所有的孩子节点,如果不是 item3 ,那么就存到 array 伪数组中。
for(let i = 0;i < allChildren.length;i++){
  if(allChildren[i] !== item3){
    array[array.length] = allChildren[i];   //数组下标一一对应存储 item 元素
    array.length+=1;
  }
}
复制代码

这个 array 是一个伪数组,它的原型链直接指向了 Object.protottype 并没有指向 Array.prototype (只有原型链中指向 Array.prototype 的数组才是真正的数组。)

  • 封装成函数 封装成一个具名函数,方便调用, return 这个数组,给我们的函数加一个参数,然后调用这个函数同时传参 item3
function getSiblings(node){
  var allChildren = node.parentNode.children;
  var array = {length:0};
  for(let i = 0;i < allChildren.length;i++){
    if(allChildren[i] !== node){
      array[array.length] = allChildren[i];
      array.length+=1;
    }
  }
return array;
}
getSiblings(item3);
复制代码
  • 再封装一个给节点添加多个 class 的函数
function addClass = function(node, classes){
  classes.forEach( (value) => node.classList.add(value) );
 };
addClass(item3, ['a','b','c']);
复制代码

调用这个函数同时传参,这样我们就可以给 item3 添加3个 class ,分别为 a , b , c

2.命名空间

现在我们有两个 API 了,但是它们看起来很分散,我们有什么办法能让这两个 API 有关联呢? 我们可以声明一个变量 window.reChenDom = {} ;

window.reChenDom = {};

reChenDom.getSiblings = function(node){
  var allChildren = node.parentNode.children;
  var array = {length:0};
  for(let i = 0;i < allChildren.length;i++){
    if(allChildren[i] !== node){
      array[array.length] = allChildren[i];
      array.length+=1;
    }
  }
  return array;
};

reChenDom.addClass = function(node, classes){
  classes.forEach( (value) => node.classList.add(value) );
 };

reChenDom.getSiblings(item3);
reChenDom.addClass(item3, ['a','b','c']);
复制代码

这就叫做 命名空间 ,也是一种 设计模式 。命名空间是非常有必要的,如果没有命名空间,有两个缺点:第一是别人不知道你的库叫什么,另一个是会不知不觉把全局对象给覆盖了。

3.能不能把 node 放在前面

接下来第三个特点,我们要用的时候特别麻烦,总是要:

reChenDom.getSiblings(item3);
reChenDom.addClass(item3, ['a','b','c']);
复制代码

能不能像下面这样每次使用都方便点呢

item3.getSiblings();
item3.addClass( ['a','b','c'] );
复制代码

有两种办法:

  1. 直接改 Node 的原型(扩展 Node 接口直接在 Node.prototype 上加函数):
Node.prototype.getSiblings = function(){
  var allChildren = this.parentNode.children;
  var array = {length:0};
  for(let i = 0;i < allChildren.length;i++){
    if(allChildren[i] !== this){
      array[array.length] = allChildren[i];
      array.length+=1;
    }
  }
  return array;
};

Node.prototype.addClass = function( classes){
  classes.forEach( (value) => this.classList.add(value) );
 };

item3.getSiblings();
item3.addClass( ['a','b','c'] );
复制代码

this 就是 getSiblings()item3.addClass( ['a','b','c'] ) 被调用时前面的对象。 其实这个函数写的不好,为什么呢?这样写是在改 Node 的属性,如果有其他人也这样写就会被覆盖。

4.把 Node2 改个名字吧

  1. jQuery 自己构造的一个函数,调用 Node 版本:
window.jQuery = function(node){
  return {
    getSiblings : function(){
    var allChildren = node.parentNode.children;
    var array = {length:0};
    for(let i = 0;i < allChildren.length;i++){
      if(allChildren[i] !== node){
        array[array.length] = allChildren[i];
        array.length+=1;
      }
    }
    return array;
    },
    addClass : function( classes){
      classes.forEach( (value) => node.classList.add(value) );
    }
  }
}

var node2 = jQuery(item3);
node2.getSiblings();
node2.addClass( ['a','b','c'] );
复制代码

这样就不仅仅可以传 Node ,也可以传其它的,比如选择器: ‘#item3’ ,所以这个名字就不叫 node 了:

window.jQuery = function(nodeOrSelector){
  let node;
    if( typeof nodeOrSelector === 'string'){
      node = document.querySelector(nodeOrSelector);
    }else{
      node = nodeOrSelector;
  };

  return {
    getSiblings : function(){
      var allChildren = node.parentNode.children;
      var array = {length:0};
      for(let i = 0;i < allChildren.length;i++){
        if(allChildren[i] !== node){
          array[array.length] = allChildren[i];
          array.length+=1;
        }
      }
      return array;
      },
      addClass : function( classes){
        classes.forEach( (value) => node.classList.add(value) );
      }
    }
}

var node2 = jQuery('#item3');
node2.getSiblings();
node2.addClass( ['a','b','c'] );
复制代码

在这里我们用到了闭包, addClass 这个函数用到了 node ,这个 node 不是函数的内部声明,那这个 node 是哪声明的呢?是在外面,如果一个函数用到了它外面的变量,那么 node 和这个匿名函数统称为闭包。

我们的 jQuery 能不能再厉害一点呢?如果我想同时操作多个 li ,给这些 li 添加 class ,怎么办呢,这个时候就不能叫 node 了,要叫 nodes ,之前的结构已经不适用了。新结构:

window.jQuery = function (nodeOrSelector){
  let nodes = {};
    if( typeof nodeOrSelector === 'string'){
      var temp = document.querySelectorAll(nodeOrSelector);
      for(let i=0; i<temp.length; i++){
        nodes[i] = temp[i];
      }
      nodes.length = temp.length;
    }else if( nodeOrSelector instanceof Node){
      nodes = { 0:nodeOrSelector,length:1 };
    }

  nodes.addClass = function(classes){
    classes.forEach( (value) => {
      for(let i=0; i<nodes.length; i++){
        nodes[i].classList.add(value);
      };
    });
  };
  return nodes;
};

var nodes = jQuery('ul>li')
nodes.addClass( ['red'] );
复制代码

5.再给个 alias

window.$ = function (nodeOrSelector){...}
var $nodes = $('ul>li')   //在变量前加上一个 $, 防止变量弄混
复制代码

那现在还可以添加几个有用的 jQueryAPI ,比如说获取/设置元素的文本:

window.$ = function (nodeOrSelector){
  let $nodes = {};
    if( typeof nodeOrSelector === 'string'){
      var temp = document.querySelectorAll(nodeOrSelector);
      for(let i=0; i<temp.length; i++){
        $nodes[i] = temp[i];
      }
      $nodes.length = temp.length;
    }else if( nodeOrSelector instanceof Node){
      $nodes = { 0:nodeOrSelector,length:1 };
    }

  $nodes.addClass = function(classes){
    classes.forEach( (value) => {
      for(let i=0; i<$nodes.length; i++){
        $nodes[i].classList.add(value);
      };
    });
  };

  $nodes.text = function(text){
    if( text === undefined ){
      var texts = [];
      for( let i=0; i<$nodes.length; i++){
        texts.push( $nodes[i].textContent )
      }
      return texts;
    }else{
      for( let i=0; i<$nodes.length; i++){
        $nodes[i].textContent = text;
      }
    }
  }

  return $nodes;
};

var $nodes = $('ul>li')
$nodes.addClass( ['red'] );
$nodes.text('hi');    //如果不给参数说明是获取text,如果给了一个参数说明是设置text
复制代码

这样我们就从封装两个函数到实现了简化版的 jQuery ,添加 class 和获取/设置文本的 API


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Mastering Regular Expressions, Second Edition

Mastering Regular Expressions, Second Edition

Jeffrey E F Friedl / O'Reilly Media / 2002-07-15 / USD 39.95

Regular expressions are an extremely powerful tool for manipulating text and data. They have spread like wildfire in recent years, now offered as standard features in Perl, Java, VB.NET and C# (and an......一起来看看 《Mastering Regular Expressions, Second Edition》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试