仿写 jQuery

在 jQuery 中,要为特定元素添加 class 很方便,只需要使用调用addClass方法即可,例如为所有 div 添加 一个叫 red 的 class 只需要写 $("div").addClass("red")。这与使用浏览器 api 实现同样的功能相比要简洁明了不少。本文通过逐渐改进的方式,实现一个从调用角度上与其类似的 api。

首先,先使用最直接的方式实现功能,传入一组节点和一个类名,为这组节点添加这个类

addClass = function (nodes, className) {
  nodes.forEach(function (el) {
    el.classList.add(className)
  })
}

let nodes = document.querySelectorAll('div')
addClass.call(undefined, nodes, 'red')

这个方式有个缺点是只能一次添加一个类,如果需要添加多个则需要调用多次,不太方便。因为我们可以借助函数中的arguments获取到传入的所有(非this)参数,所以 className 这个参数也可以舍去,下面是可以一次性添加多个类的实现。

addClass = function (nodes) {
  let args = arguments
  nodes.forEach(function (el) {
    for (let i = 1; i < args.length; i++) {
      el.classList.add(args[i])
    }
  })
}

let nodes = document.querySelectorAll('div')
addClass.call(undefined, nodes, 'red', 'foo')

对比 jQuery 中的实现可以发现,这里每次都要先获取到节点然后再操作,而使用 jQuery 则一般直接传入选择器。所以这里可以进一步改造,使其适应选择器和节点参数。

addClass = function (nodeOrSelector) {
  let args = arguments
  if (typeof nodeOrSelector === 'string') {
    nodes = document.querySelectorAll(nodeOrSelector)
  } else {
    nodes = nodeOrSelector
  }
  nodes.forEach(function (el) {
    for (let i = 1; i < args.length; i++) {
      el.classList.add(args[i])
    }
  })
}

addClass.call(undefined, 'div', 'red', 'foo')

到这里,实际上与 jQuery 的 api 已经有几分相似之处了,但是这里有一个明显的问题,那就是如果用户自己也定义了一个 addClass,那么我们的 addClass 就会被覆盖掉。因此,我们应该创建一个“独立的区域”用来存放这个函数。

window.$ = {
  addClass: function (nodeOrSelector) {
    let args = arguments
    if (typeof nodeOrSelector === 'string') {
      nodes = document.querySelectorAll(nodeOrSelector)
    } else {
      nodes = nodeOrSelector
    }
    nodes.forEach(function (el) {
      for (let i = 1; i < args.length; i++) {
        el.classList.add(args[i])
      }
    })
  }
}

$.addClass.call(undefined, 'div', 'red', 'foo')

改完以后和 jQuery 更像了,就差最后几步了。实际上,如果我们执行typeof $(在引入了 jQuery的前提下),可以发现它实际上是个函数。也就是说其实应该模仿它,将上面的代码也封装成一个函数。完成后的完整代码如下:

// index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .red {color: red; background-color: black;}
    </style>
</head>
<body>
<div>DIV1</div>
<div>DIV2</div>
<div>DIV3</div>
<script src="./main.js"></script>
</body>
</html>

// main.js
window.jQuery = function (nodeOrSelector) {
  let nodes

  if (typeof nodeOrSelector === 'string') {
    nodes = document.querySelectorAll(nodeOrSelector)
  } else {
    nodes = {
      0: nodeOrSelector,
      length: 1,
    }
  }

  nodes.addClass = function () {
    let classArray = arguments
    nodes.forEach(function (el) {
      for (let className of classArray ){
        el.classList.add(className)
      }
    })
  }

  return nodes
}

window.$ = window.jQuery

setTimeout(function () {
  let $div = $('div')
  $div.addClass('red', 'foo', 'bar')
}, 1000)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。