在 jQuery 中,要為特定元素添加 class 很方便,只需要使用調(diào)用addClass方法即可,例如為所有 div 添加 一個(gè)叫 red 的 class 只需要寫 $("div").addClass("red")。這與使用瀏覽器 api 實(shí)現(xiàn)同樣的功能相比要簡(jiǎn)潔明了不少。本文通過逐漸改進(jìn)的方式,實(shí)現(xiàn)一個(gè)從調(diào)用角度上與其類似的 api。
首先,先使用最直接的方式實(shí)現(xiàn)功能,傳入一組節(jié)點(diǎn)和一個(gè)類名,為這組節(jié)點(diǎn)添加這個(gè)類
addClass = function (nodes, className) {
nodes.forEach(function (el) {
el.classList.add(className)
})
}
let nodes = document.querySelectorAll('div')
addClass.call(undefined, nodes, 'red')
這個(gè)方式有個(gè)缺點(diǎn)是只能一次添加一個(gè)類,如果需要添加多個(gè)則需要調(diào)用多次,不太方便。因?yàn)槲覀兛梢越柚瘮?shù)中的arguments獲取到傳入的所有(非this)參數(shù),所以 className 這個(gè)參數(shù)也可以舍去,下面是可以一次性添加多個(gè)類的實(shí)現(xiàn)。
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')
對(duì)比 jQuery 中的實(shí)現(xiàn)可以發(fā)現(xiàn),這里每次都要先獲取到節(jié)點(diǎn)然后再操作,而使用 jQuery 則一般直接傳入選擇器。所以這里可以進(jìn)一步改造,使其適應(yīng)選擇器和節(jié)點(diǎn)參數(shù)。
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')
到這里,實(shí)際上與 jQuery 的 api 已經(jīng)有幾分相似之處了,但是這里有一個(gè)明顯的問題,那就是如果用戶自己也定義了一個(gè) addClass,那么我們的 addClass 就會(huì)被覆蓋掉。因此,我們應(yīng)該創(chuàng)建一個(gè)“獨(dú)立的區(qū)域”用來存放這個(gè)函數(shù)。
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 更像了,就差最后幾步了。實(shí)際上,如果我們執(zhí)行typeof $(在引入了 jQuery的前提下),可以發(fā)現(xiàn)它實(shí)際上是個(gè)函數(shù)。也就是說其實(shí)應(yīng)該模仿它,將上面的代碼也封裝成一個(gè)函數(shù)。完成后的完整代碼如下:
// 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)