1. 封装函数
使用原生DOM API以实现【获取所有同类元素并加上同一样式】时,代码如下。
<body>
<div id="item1">选项1</div>
<div id="item2">选项2</div>
<div id="item3">选项3</div>
<div id="item4">选项4</div>
<div id="item5">选项5</div>
</body>
function getSiblings(node) {
var allChildren = node.parentNode.children
var array = {
length: 0
}
for (let i = 0; i < allChildren.length; i++) {
if (allChildren[i] !== node) {
array[array.length] = allChildren[i]
array.length += 1
}
}
return array
}
function addClass(node, classes){
for(let key in classes){
var value = classes[key]
if(value){
node.classList.add(key)
}else{
node.classList.remove(key)
}
}
}
此处,为了代码段的复用性,封装为getSiblings()
与addClass()
函数。
2. 使node可以放在前面而不是作为参数传入
方法一:扩展 Node 接口,直接在 Node.prototype 上加函数
缺点:可能会覆盖原有的 Node.prototype 的函数
Node.prototype.getSiblings = function() {
var allChildren = this.parentNode.children
var array = {
length: 0
}
for (let i = 0; i < allChildren.length; i++) {
if (allChildren[i] !== this) {
array[array.length] = allChildren[i]
array.length += 1
}
}
return array
}
Node.prototype.addClass = function(classes){
classes.forEach((value) => this.classList.add(value))
}
方法二:创建命名空间可以很好的避免全局变量名冲突。
window.Node2 = function(node){
return {
getSiblings: function(){
var allChildren = node.parentNode.children
var array = {
length: 0
}
for(let i=0;i<allChildren.length;i++){
if(allChildren[i]!==node){
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()
3. 将该命名改为jQuery
window.jQuery = function(nodeOrSelector) {
let node
if (typeof nodeOrSelector === 'string') {
node = document.querySelector(nodeOrSelector)
} else {
node = nodeOrSelector
}
return {
getSiblings: function() {
var allChildren = node.parentNode.children
var array = {
length: 0
}
for (let i = 0; i < allChildren.length; i++) {
if (allChildren[i] !== node) {
array[array.length] = allChildren[i]
array.length += 1
}
}
return array
},
addClass: function(classes) {
classes.forEach((value) => node.classList.add(value))
}
}
}
var node2 = jQuery('div:nth-child(3)')
node2.getSiblings()
node2.addClass(['red', 'b', 'c'])
4. 完成一个模仿jQuery的API
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 (nodeOrSelector instanceof Node) {
nodes = {
0: nodeOrSelector,
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 = jQuery('div')
node2.addClass(['red', 'b', 'c'])
node2.text('hi')
此时已经可以使用jQuery(selector)
与方法addClass()
、text()
来便利地满足一些需求了,但是由于这里jQuery
写起来太费劲,再为它设置一个缩写$
window.$ = function(nodeOrSelector) {
let nodes = {}
……
nodes.addClass = function(){ }
return nodes
}
此后只需$(selector)
就可以轻松愉悦地定位元素以及使用封装好的函数了
5. 总结
实现简易的jQuery的API后容易发现,jQuery就是一个封装好的函数库,将原生JS的各种API重新写成了高效率,高语义化,高兼容性的API,给开发带来了非常大的便利。