jQuery从入门到精通 封装函数到实现简化版jQuery
沉沙 2018-07-24 来源 : 阅读 1176 评论 0

摘要:本篇jQuery教程探讨了封装函数到实现简化版jQuery,希望阅读本篇文章以后大家有所收获,帮助大家对jQuery的理解更加深入。

需求分析

· 获取一个节点的所有兄弟;

· 给一个节点添加加多个 class;

· DOM的API实现比较繁琐,所以自己封装 API ;

功能实现

1.封装函数

· 获取兄弟
操作步骤:
在 html 中有一个 ul 标签,在 ul 中有 5 个 li 。

<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>

· 获取 id 为 item3 的兄弟元素。
首先定义一个 allChildren 变量来存储 item3 的父节点所有的子元素;

var allChildren = item3.parentNode.children;

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

var array = {length:0};

· 遍历所有的孩子节点,如果不是 item3 ,那么就存到 arr 数组中。

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版本:(新的接口 BetterNode,接上面的第二种方法)

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')   //在变量前加上一个 $, 防止变量弄混

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

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

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

 

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标WEB前端jQuery频道!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程