先寫段代碼
var dom = {}
dom.getSiblings(node)
dom.addClass(node, {a: true, b: false})
dom就是命名空間,一個(gè)對(duì)象,對(duì)后面的封裝和理解有幫助
<ul>
<li id="item1">選項(xiàng)1</li>
<li id="item2">選項(xiàng)2</li>
<li id="item3">選項(xiàng)3</li>
<li id="item4">選項(xiàng)4</li>
<li id="item5">選項(xiàng)5</li>
</ul>
var allChildren = item3.parentNode.children
var array = {length:0}
for(let i = 0;i < allChildren.length; i++){
if(allChildren[i] !== item3){
array[array.length] = allChildren[i]; //不是數(shù)組沒(méi)有push方法
array.length += 1
}
}
console.log(array)
上面的代碼實(shí)現(xiàn)的效果是獲得節(jié)點(diǎn)的兄弟姐妹
console.log輸出的是除了item3以外的其他兄弟節(jié)點(diǎn),即item1, #item2, item4, #item5
接下來(lái)把代碼進(jìn)行封裝
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
}
console.log(getSiblings(item3))
接下來(lái)增加實(shí)現(xiàn)刪除添加class類功能的代碼
var classes = {'a':true,'b':false,'c':true}
for( let key in classes ){
var value = classes[key]
if(value){
item3.classList.add(key)
}else{
item3.classList.remove(key)
}
}
我們通過(guò)審查元素item3就可以看到item3上多了a和b的class類,
封裝刪除添加class類的代碼
function addClass(node,classes) {
for (let key in classes) {
var value = classes[key]
if (value) {
node.classList.add(key)
} else {
node.classList.remove(key)
}
}
}
addClass(item3,{'a':true,'b':false,'c':true})
將上面兩個(gè)方法代碼合并整合,來(lái)實(shí)現(xiàn)同樣的效果
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]; //不是數(shù)組沒(méi)有push
array.length += 1
}
}
return array
}
function addClass(node,classes) {
for (let key in classes) {
var value = classes[key]
var methodName = value ? 'add': 'remove'
node.classList[methodName](key)
}
}
window.xzdom = {}
xzdom.getSiblings = getSiblings
xzdom.addClass = addClass
xzdom.getSiblings(item3)
xzdom.addClass(item3,{'a':true,'b':false,'c':true})
上面代碼的最后五行就命名空間, 是一種設(shè)計(jì)模式
命名空間非常有必要,如果沒(méi)有命名空間有兩個(gè)缺點(diǎn)1.別人不知道叫什么2.會(huì)不知不覺(jué)覆蓋全局變量。
而jQuery就是用了命名空間的模式來(lái)實(shí)現(xiàn)的。
下面正式引出了jQuery的設(shè)計(jì)原理
首先我們?cè)谠蜕霞?,Node.prototype原型上加
<ul>
<li id="item1">選項(xiàng)1</li>
<li id="item2">選項(xiàng)2</li>
<li id="item3">選項(xiàng)3</li>
<li id="item4">選項(xiàng)4</li>
<li id="item5">選項(xiàng)5</li>
</ul>
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) )
} //移除class的功能取消了,保留了addclass功能
console.log( item3.getSiblings() )
// 等價(jià)于 console.log(item3.getSiblings.call(item3)) //this作為第一個(gè)參數(shù)
item3.addClass( ['a','b','c'] )
// 等價(jià)于 item3.addClass.call(item3, ['a','b','c'] ) //['a','b','c']作為第二個(gè)參數(shù)
這里實(shí)現(xiàn)了在node原型上的添加class的功能,但是有個(gè)問(wèn)題,它會(huì)覆蓋全局變量的方法,比如原型上有getSiblings這個(gè)方法或者屬性,那么這里就會(huì)覆蓋掉。
其次通過(guò)修改名稱來(lái)保留原來(lái)的方法或?qū)傩?--新建一個(gè)Node2(或者叫jQuery)
window.jQuery = function(node) { //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]; //不是數(shù)組沒(méi)有push
array.length += 1
}
}
return array
},
addClass: function(classes) {
classes.forEach((value) => node.classList.add(value))
}
}
}
var node2 = jQuery(item3) //var node2 = Node2(item3)
console.log(node2.getSiblings())
node2.addClass(['a', 'b', 'c'])
代碼就實(shí)現(xiàn)了在item3上添加了a,b,c三個(gè)class類
Node2(jQuery)接受一個(gè)舊的節(jié)點(diǎn),然后返回一個(gè)新的對(duì)象,這個(gè)對(duì)象就是Node2(jQuery)對(duì)象
下面加上選擇器
.blue{color:blue}
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]; //不是數(shù)組沒(méi)有push
array.length += 1
}
}
return array
},
addClass: function(classes) {
classes.forEach((value) => node.classList.add(value))
}
}
}
var node2 = jQuery('ul>li:nth-child(3)') // var node2 = jQuery('#item3')
console.log(node2.getSiblings())
node2.addClass(['blue', 'b', 'c'])
代碼實(shí)現(xiàn)了在item3上添加blue,b,c三個(gè)class類,并且blue類有樣式,并且item3的li變藍(lán)
同時(shí)操作6個(gè)li
.blue{color:blue;}
<ul>
<li id="item1">選項(xiàng)1</li>
<li id="item2">選項(xiàng)2</li>
<li id="item3">選項(xiàng)3</li>
<li id="item4">選項(xiàng)4</li>
<li id="item5">選項(xiàng)5</li>
</ul>
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.getText = function() {
var texts = []
for (let i = 0; i < nodes.length; i++) {
texts.push(nodes[i].textContent)
}
return texts
}
nodes.setText = function(text) {
for (let i = 0; i < nodes.length; i++) {
nodes[i].textContent = text
}
}
return nodes
}
var node2 = jQuery('ul > li')
node2.addClass(['blue'])
console.log(node2.getText())
node2.setText('hi')
通過(guò)全局變量的jQuery的setText方法就把6個(gè)li變藍(lán)了
把getText和setText方法放在同一個(gè)函數(shù)封裝
nodes.text = function(text) {
if (text === undefined) { //元素的文本內(nèi)容
var texts = []
for (let i = 0; i < nodes.length; i++) {
texts.push(nodes[i].textContent)
}
return texts
} else { //替換文本內(nèi)容,并用傳進(jìn)來(lái)的值覆蓋
for (let i = 0; i < nodes.length; i++) {
nodes[i].textContent = text
}
}
}
這里的設(shè)置文本內(nèi)容和jQuery很像,傳一個(gè)參數(shù),如果是undefined,就獲取元素本是的文本內(nèi)容;如果有內(nèi)容就替換文本內(nèi)容,用用傳進(jìn)來(lái)的值覆蓋。
我們可以看出 jQuery是函數(shù)(有括號(hào),6種數(shù)據(jù)類型不符合,只能是對(duì)象里的函數(shù)這個(gè)類型符合)。并且是鏈?zhǔn)讲僮?,因?yàn)樯厦娴拇a在node的原型鏈上線指向了構(gòu)造出來(lái)的jQuery的原型,然后再指向Object.prototype
習(xí)俗:如果這個(gè)對(duì)象是由jQuery構(gòu)造出來(lái)的或者是$構(gòu)造出來(lái)的,就在對(duì)象前面加$,表示它是jQuery的對(duì)象