HTML 如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<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>
</body>
</html>
首先封装两个函数
// 获取除自身以外的所有兄弟节点
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[i],因为 i !== 3,伪数组下标会产生间隔
array.length += 1
}
}
return array
}
console.log(getSiblings(item3)) // {0: li#item1, 1: li#item2, 2: li#item4, 3: li#item5, length: 4}
// 给一个节点同时加上多个类名
function addClass(node, classes) {
classes.forEach((value) => node.classList.add(value))
}
addClass(item3, ['a', 'b', 'c'])
命名空间
给这两个函数分别命名,避免出现同名函数互相覆盖的情况
window.zydom = {} // 声明一个全局对象
zydom.getSiblings = function(node) { // zydom.getSiblings 表示全局对象 zydom 中有一个 getSiblings 属性,然后声明一个函数并赋值给它
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
}
zydom.addClass = function(node, classes) { // zydom.addClass 表示全局对象 zydom 中有一个 addClass 属性,然后声明一个函数并赋值给它
classes.forEach((value) => node.classList.add(value))
}
// 调用函数
zydom.getSiblings(item3)
zydom.addClass(item3, ['a', 'b', 'c'])
虽然避免了同名函数互相覆盖的情况,但我们觉得zydom.getSiblings(item3)
调用函数的写法不够简洁,能不能写成item.getSiblings()
这种形式呢?
把 node 放在前面
node.getSiblings()
node.addClass()
方法一:扩展 Node 接口
直接在 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) )
}
item3.getSiblings() // 相当于 this.getSiblings(),这里的 this 传入的就是 item3
// 等价于 item3.getSiblings.call(item3)
item3.addClass(['a','b','c'])
// 等价于 item3.addClass.call(item3, [abc])
同样地,直接在 Node.prototype 上加函数这种方法也会有同名函数相互覆盖的情况发生,因此采用下面的方法二
方法二:新的接口 BetterNode「无侵入」
给 node 一个新的名字 node2
function Node2(node) {
return {
element: node,
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))
}
}
}
let node =document.getElementById('item3')
let node2 = Node2(node) // 函数 Node2() 接受一个 node ,然后返回一个新的对象给 node2
node2.getSiblings() // 这里的 this 是 node2,因此 Node2 函数里不能用 this
node2.addClass(['a','b','c'])
把 Node2 改个名字吧
function jQuery(node) {
return {
element: node,
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))
}
}
}
let node =document.getElementById('item3')
let node2 = jQuery(node)
console.log(node2.getSiblings())
node2.addClass(['a','b','c'])
再给它一个缩写 alias
改进一:改掉 document.getElementById
改进二:可以接收多个 node
改进三:添加 .text()
window.$ = jQuery
window.jQuery = function(nodeOrSelector) {
let nodes = {} // 伪数组
/*做类型检测*/
if (typeof nodeOrSelector === 'string') {
let temp = document.querySelectorAll(nodeOrSelector) // 这里使用临时变量 temp 是为了不让 nodes 返回 NodeList,而是直接返回一个 Object
for (let i = 0; i < temp.length; i++) {
nodes[i] = temp[i]
}
nodes.length = temp.length
} else if (nodeOrSelector instanceof Node) {
nodes = {
0: nodeOrSelector, // nodes[0] 就表示这个节点
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) { // getText
var texts = [] // 数组
for (let i = 0; i < nodes.length; i++) {
texts.push(nodes[i].textContent)
}
} else { // setText
for (let i = 0; i < nodes.length; i++) {
nodes[i].textContent = text
}
}
}
return nodes // 返回一个伪数组 {0: li, 1: li, length: 5, addClass: f, text: f}
}
window.$ = jQuery
var $nodes = $('ul > li')
$nodes.addClass(['red'])
$nodes.text('hi')
http://js.jirengu.com/qekomedetu/1/edit?html,js,output
总结
jQuery 实质上是一个构造函数,它接受一个参数(可能是节点、选择器、字符串),然后返回一个新的对象(API)去操作节点。
网友评论