美文网首页
自己动手构造API理解jQuery

自己动手构造API理解jQuery

作者: kiterumer | 来源:发表于2019-04-10 20:15 被阅读0次

    封装两个函数,一个用来获取某个节点的兄弟姐妹,一个用来给元素添加类
    现在有一个无序列表。循序渐进,体会jQuery设计思想。

    <!-- ul>li[id=item$]{选项$}*5 -->
        <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>
    

    封装两个函数

    封装一个获取兄弟姐妹函数getSiblings

    function getSiblings(node){  /* API */
        var allChildren = node.parentNode.children ;
        // 伪数组
        var array = {
            length: 0
        }
        // 获取node的兄弟姐妹
        for (let i = 0; i < allChildren.length; i++){
            if(allChildren[i] !== node){
                // array是伪数组,没有push方法
                array[array.length] = allChildren[i];
                array.length += 1;
            }
        }
        return array
    }
    

    封装添加类函数addClass

    //添加的类用数组表示
    function addClass(node,classes){
        classes.forEach(value => {
            node.classList.add(value)
        });
    }
    

    命名空间

    两个函数不能就这么随意的放着,赋予一个命名空间

    // getSiblings,addClass作为yyydom对象的方法
    window.yyydom = {}
    yyydom.getSiblings = getSiblings
    yyydom.addClass = addClass
    
    yyydom.addClass(item2,['a','b'])
    //这种调用方式并不好,我们希望将node节点放在前面
    

    把node放在前面进行调用

    有两种方法:

    1. 扩展 Node 接口,直接在 Node.prototype 上加函数
    2. 自己创建新的接口

    1.篡改Node.prototype,添加函数

    Node.prototype.getSiblings = function(){
     var allChildren = this.parentNode.children ;
        // 伪数组
        var array = {
            length: 0
        }
        // 获取node的兄弟姐妹
        for (let i = 0; i < allChildren.length; i++){
            if(allChildren[i] !== this){
                // array是伪数组,没有push方法
                array[array.length] = allChildren[i];
                array.length += 1;
            }
        }
        return array
    }
    
    Node.prototype.addClass2 = function(classes){
     classes.forEach(value => {
            this.classList.add(value)
        });
    }
    // 用call显示this,call的第一个参数就是this
    // item3.getSiblings()
    // item3.getSiblings.call(item3) ,等价上
    // item3.addClass(['q','w','e'])
    // item3.addClass(item3,['q','w','e'])  等价上
    

    但是,在Node原型上增加方法也不好,如果有多个人修改容易造成冲突。既然这样,不如自己创建一个新Node构造函数。自己动手,丰衣足食。

    2.自己创建新的接口(无侵入)

    window.Node2 = function(node){
        return {
            getSiblings:function(){
                var allChildren = node.parentNode.children ;
                // 伪数组
                var array = {
                length: 0
                }
                // 获取node的兄弟姐妹
                for (let i = 0; i < allChildren.length; i++){
                if(allChildren[i] !== node){
                // array是伪数组,没有push方法
                array[array.length] = allChildren[i];
                array.length += 1;
                }
                }
                return array
            },
            addClass:function(classes){
                classes.forEach(value => {
                    node.classList.add(value)
                });
            }
        }
    }
    var node2 = Node2(item3)
    node2.getSiblings()
    node2.addClass(['p','o'])
    

    构造函数Node2返回一个新对象,这个对象有getSiblings和addClass两个方法,里面还是调用的原生API。似乎离目标越来越近了。

    Node2是随意取的,改为jQuery,于是

    var node2 = jQuery(item3)
    node2.getSiblings()
    

    再进一步,window.$ = jQuery,再省略window,于是就变成了

    var node2 = $(item3)
    node2.getSiblings()
    

    是不是很熟悉呢?

    选择器多样化

    目前我们所创建的构造函数只能获取节点,如果是其他选择器呢,比如$('ul>li:nth-child(3)'),那么需要加一些判断

    window.jQuery = function(nodeOrSelector){
        //是否为字符串
        if(typeof nodeOrSelector === 'string'){
      //利用了原生的document.querySelector
            node = document.querySelector(nodeOrSelector)
        }else{
            node = nodeOrSelector
        }
    
        return {
            getSiblings:function(){
                var allChildren = node.parentNode.children ;
                // 伪数组
                var array = {
                length: 0
                }
                // 获取node的兄弟姐妹
                for (let i = 0; i < allChildren.length; i++){
                if(allChildren[i] !== node){
                // array是伪数组,没有push方法
                array[array.length] = allChildren[i];
                array.length += 1;
                }
                }
                return array
            },
            addClass:function(classes){
                classes.forEach(value => {
                    node.classList.add(value)
                });
            }
        }
    
    }
    
    //获取列表第五个元素
    var node2 = jQuery('ul>li:nth-child(5)')
    // 给我旧的对象,返回新的对象
    node2.addClass(['red'])
    

    那么要获取多个节点呢,这是里面就要用到document.querySelectorAll,而且部分逻辑也有变化

    window.jQuery2 = function(nodeOrSelector){
        let nodes  //最后要返回的对象
        if(typeof nodeOrSelector === 'string'){
            nodes = document.querySelectorAll(nodeOrSelector) //伪数组
        }else if(nodeOrSelector instanceof Node){
            // 保证返回结果一致,都为伪数组
            nodes = {
                0: nodeOrSelector,
                length: 1
            }
        }
       //添加类
        nodes.addClass = function(classes){
            classes.forEach((value) => {
                // 给nodes数组里每一项添加类
                for (let i = 0;i < nodes.length; i++){
                    nodes[i].classList.add(value)
                }
            })
        }
        // 获取元素文本
        nodes.getText = function(){
            var texts = []
            for(let i = 0;i < nodes.length;i++){
                texts.push(nodes[i].textContent)
            }
            return texts
        }
        // 设置文本
        nodes.setText = function(text){
            for(let i=0;i<nodes.length;i++){
                nodes[i].textContent = text
            }
        }
        // 两者合并,这种在jQuery中非常常见
        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 node3 = jQuery2('ul>li')
    node3.addClass(['red'])
    node3.text('yyy')
    //这大概就是最终体了
    

    相关文章

      网友评论

          本文标题:自己动手构造API理解jQuery

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