美文网首页
实现一个jquery api

实现一个jquery api

作者: lyp82nkl | 来源:发表于2019-06-20 02:51 被阅读0次

    jQuery是一个快速、简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架)。jQuery设计的宗旨是“write Less,Do More”,即倡导写更少的代码,做更多的事情。它封装JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作、事件处理、动画设计和Ajax交互。
    jQuery的核心特性可以总结为:具有独特的链式语法和短小清晰的多功能接口;具有高效灵活的css选择器,并且可对CSS选择器进行扩展;拥有便捷的插件扩展机制和丰富的插件。

    jQuery本质

    Query实质上是一个构造函数,该构造函数接受一个参数,jQuery通过这个参数利用原生API找到节点,之后返回一个方法对象,该方法对象上的方法对节点进行操作(方法使用了闭包)。

    封装函数

    <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>
    
    1. 获取某一标签的全部兄弟元素
    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 += 1;
       }
    }
    return arr;
    }
    
    • DOM API 中的ParentNode.children属性,返回该节点的所有元素孩子。
    • 返回节点父亲的所有孩子,然后遍历这个伪数组(children属性返回一个HTMLCollection实例,是一个伪数组),将不等于自身节点的其他节点放入一个空对象里。
    • 声明的arr是一个伪数组,所以在遍历后不能使用数组的push方法,那么怎么把value放进数组呢?所以使用array[array.length]=allChildren[i]的方法
    2. 给一个标签添加多个class
    function addClass(node,classes){
      for(var key in classes){
        var value = classes[key];
        if(value){
          node.classList.add(key);
        }else{
          node.classList.remove(key)
        }
      }
    }
    

    以上两个函数,我们就可以直接对它们传参进行操作:

    //得到除item2的全部兄弟元素
    console.log(getSiblings(item2))
    //给item2添加a,c两个类
    addClass(item2,{a:true,b:false,c:true})
    

    命名空间

    我们获得了两个函数:getSiblings() , addClass() ,他们都是操纵节点,那我们能把他们联系起来吗?所以我们可以把他们放到一个库里,给它命名,这就叫命名空间。

    window.ldom = {}
    ldom.getSiblings(node)
    ldom.addClass(node,classes)
    
     var ldom = {}//声明一个名字为ldom的空间
    ldom.getSiblings = function(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 += 1;
      }
    }
    return arr;
    }
    ldom.addClass = function(node,classes){
      for(var key in classes){
        var value = classes[key];
        var method =value ? 'add' : 'remove';
        node.classList[method](key);
      }
    }
    console.log(ldom.getSiblings(item3));
    ldom.addClass(item3,{a:true,b:false,c:true})
    
    • 封装命名空间就是把所有封装的函数放入一个对象之中,通过调用对象的方法来调用封装的函数。 这样做有一个好处:不会污染全局变量

    将 node 放在前面

    node.getSiblings()
    node.addClass()
    
    方法一:扩展 Node 接口

    直接在 Node.prototype 上加函数

    Node.prototype.getSiblings=function(){
      //this就是Node构造函数的实例对象,也就是节点
      var allChildren = this.parentNode.children;
      var arr = {
        length: 0
      };
    for(var i =0;i<allChildren.length;i++){
      if(allChildren[i] !== this){
        arr[arr.length] = allChildren[i]; 
        arr.length += 1;
      }
    }
    return arr;
    }
    Node.prototype.addClass = function(classes){
      for(var key in classes){
        var value = classes[key];
        var method =value ? 'add' : 'remove';
       this.classList[method](key);
      }
    }
    console.log(item3.getSiblings.call(item3))  //item3就是节点也就是Node的实例对象,它的下划线原型指向Node.prototype
    item3.addClass.call(item3,{a:true,b:false,c:true})
    
    • 直接在 Node 对象上添加封装函数,修改Node.protorype对象,在Node.prototype对象上新增方法。
    • 缺点:修改 Node 对象的原型,可能无意识覆盖原生API
    方法二:创建一个新的接口函数
    window.Node2 = function(nodesSelect){
      let nodes = {};
      if(typeof nodesSelect === 'string'){
        let temp = document.querySelectorAll(nodesSelect);//利用一个新的中间变量的到一个干净的伪数组(下划线原型直接执行Object)
        for(let i =0;i<temp.length;i++){
          nodes[i]= temp[i]
        }
        nodes.length = temp.length;  }else if(nodesSelect instanceof Node){
        nodes = {   //这里之所以写成一个伪数组,是为了下面遍历它
          0: nodesSelect,
          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 node2 = Node2(item3);
    node2.addClass(['blue'])
    
    • 优点不会覆盖原有的api,方便调用

    将Node2 改个名字

    function jQuery(node){
        return {
            element: node,
            getSiblings: function(){
    
            },
            addClass: function(){
    
            }
        }
    }
    let node =document.getElementById('x')
    let node2 =jQuery(node)
    node2.getSiblings()
    node2.addClass()
    

    再给个缩写 alias

    window.$ = jQuery
    
    //$=jQuery也是可以的
    

    这时就可以直接通过$('item2')来调用了,也就达到了类型jquery的效果

    DOM对象跟jQuery对象相互转换

    jQuery对象转换成DOM对象:

    • 方式一:$(“#btn”)[0]

    • 方式二:$(“#btn”).get(0)

    DOM对象转换成jQuery对象:
    • $(document) -> 把DOM对象转成了jQuery对象

    • var btn = document.getElementById(“btn”);

    • btn -> $(btn);

    相关文章

      网友评论

          本文标题:实现一个jquery api

          本文链接:https://www.haomeiwen.com/subject/edjrqctx.html