自己写一个 jQuery

作者: 养乐多__ | 来源:发表于2019-04-26 20:20 被阅读4次

    jQuery 是目前使用最广泛的 JavaScript 函数库,它提供的 API 易于使用且功能强大。我们也可以模仿 jQuery 写一个函数库,封装一些实现特定功能的函数。

    一、封装两个函数

    我们先封装两个常用的函数:

    1. 给某个节点添加类名
    function addClass(node, class1) { 
        node.classList.add(class1)
    }
    

    假设给节点 nodeX 添加类名为 red:addClass(nodeX, 'red')

    1. 给某个节点设置文本内容
    function setText(node, text) { 
        node.textContent = text
    }
    

    假设给节点 nodeX 设置文本内容为 hi:setText(nodeX, 'hi')

    二、命名空间

    “命名空间”是一种设计模式,即把自己写的函数放在一个库里并给它命名,它们就不会与已有的相同标识符发生冲突。例:给上述两个函数命名为 gydom

    window.gydom = {……}
    gydom.addClass = addClass
    gydom.setText = setText
    // 函数调用
    gydom.addClass(nodeX, 'red' )
    gydom.setText(nodeX, 'hi')
    

    三、改写为 Node.prototype

    扩展 Node 接口,直接在 Node.prototype 上添加函数,用 this 传参,方便调用。

    Node.prototype.addClass = function(class1) { 
        this.classList.add(class1)
    }
    Node.prototype.setText = function(text) { 
        this.textContent = text
    }
    // 调用函数
    nodeX.addClass.call(nodeX, 'red') // 等价于 nodeX.addClass('red')
    nodeX.setText.call(nodeX, 'hi')  // 等价于 nodeX.getSiblings('hi') 
    

    nodeX.function.call(nodeX) 为显示执行 this
    nodeX.function() 为隐式执行 this

    function.call() 的第一个参数,会被当做 this 来执行。新手最好用 call() 调用函数,可以加深对 this 的理解。

    四、改写为 Node2

    虽然在 Node.prototype 上定义函数方便使用,但是有很大的弊端,不同的人定义的函数会相互覆盖,比较杂乱,所以我们可以重写一个新的接口 Node2,再用它新提供的 API 去操控节点。

    window.Node2 = function(node){
      return {
        addClass: function(node, class1) { 
          node.classList.add(class1)
        },
        setText: function(node, text) { 
          node.textContent = text
        }
      }
    }
    // 调用函数
    var node2 = Node2(nodeX)
    node2.addClass('red')
    node2.setText('hi')
    

    这种方法叫做“无侵入”。

    五、改名为 jQuery

    • 将函数名 Node2 改为 jQuery,函数体不做改动,还是实现同样的效果。
    window.jQuery= function(node){
      return {
        addClass: function(){……},
        setText: function(){……}
      }
    }
    // 调用函数
    var node2 = jQuery(nodeX)
    node2.addClass('red')
    node2.setText('hi')
    

    jQuery 其实相当于一个构造函数,它接受参数,然后返回一个新的对象,并调用新对象的 API 去操作接受的元素。

    • jQuery 接受的参数不仅可以是节点,还可以是字符串:
    window.jQuery = function(nodeOrSelector){
      let node
      if(typeof nodeOrSelector === 'string'){ // 判断参数类型
        node = document.querySelector(nodeOrSelector) // 根据参数找对应节点
      }else{
        node = nodeOrSelector // 直接将字符串地址赋值给 node
      }
      return {
        addClass: function(){……}
        setText: function(){……},
      }
    }
    // 调用
    var node2 = jQuery ('#xxx') // 获取页面中 id 为 xxx 的元素
    node2.addClass({'red')
    node2.setText('hi')
    

    六、jQuery 操作多个节点

    // 接受一个 Node 或选择器
    window.jQuery = function(nodeOrSelector) {
        // 封装成一个伪数组
        let nodes = {}
        if (typeof nodeOrSelector === 'string') {
          let temp = document.querySelectorAll(nodeOrSelector) // 伪数组
          for (let i = 0; i < temp.length; i++) {
            nodes[i] = temp[i]
          }
          nodes.length = temp.length
        } else if (nodeSelector instanceof Node) {
          nodes = {
            0: nodeOrSelector,
            length: 1
          }
        }
        // API
        nodes.addClass = function(class1) { 
          for (let i = 0; i < nodes.length; i++) {
            nodes[i].classList.add(class1)
          }
        }
        // API 
        nodes.setText = function(text) { 
          for (let i=0; i<nodes.length; i++) {
            nodes[i].textContent = text
          }
        }
        // 返回伪数组 nodes
        return nodes
    }
    // 调用
    var nodes = jQuery('li')  // 页面中的 li 标签
    nodes.addClass('red')
    nodes.setText('hi')
    

    七、alias $

    我们可以给 jQuery 一个别名 $,使调用时更简洁方便:

    window.$ = jQuery
    

    如果一个对象是由 jQuery 构造出来的,最好在对象名字前面加上 $,表示它是 jQuery 的对象,避免与 DOM 对象混淆而用错方法。

    var nodes = jQuery('li')
    // 改写为
    var $nodes = $('li')
    $nodes.addClass('red')
    $nodes.setText('hi')
    

    这样,封装完的 jQuery 函数就是具有一定功能的 API,可以供自己和他人调用了。

    相关文章

      网友评论

        本文标题:自己写一个 jQuery

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