$.fn.get
從當前對象集合中獲取所有元素或單個元素。當index參數不存在的時,以普通數組的方式返回所有的元素。當指定index時,只返回該置的元素。這點與eq不同,該方法返回的是DOM節點,不是Zepto對象集合。
get: function(idx){
return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length]
},
// 這裏用的是三目運算符,我們可以簡單的改寫一下
get: function(idx) {
if(idx === undefined) {
// 沒有設置 idx 返回全部的元素
return slice.call(this)
// this.slice()
} else {
// 設置了 idx 的情況,取對應的元素
if(idx >= 0) {
// idx 大於等於0 從頭開始取
return this[idx]
} else {
// idx 小於0 從尾開始取
return this[idx + this.length]
}
}
}
$.fn.toArray
這是一個彩蛋驚喜,本質是暴露出來的,不過官方的API文檔上並沒有。其主要是內部使用,用於調用 $.fn.get 把傳入的 zepto 對象轉化成一個數組。
toArray: function(){ return this.get() },
$.fn.concat
添加元素到一個Zepto對象集合形成一個新數組。如果參數是一個數組,那麼這個數組中的元素將會合併到Zepto對象集合中。
concat: function(){
var i, value, args = []
// 遍歷傳入的參數
for (i = 0; i < arguments.length; i++) {
value = arguments[i]
// 檢測元素是不是 zepto 對象,如果是,那麼轉化成數組插入到 臨時數組中,如果是元素,那麼直接插入到臨時數組中
args[i] = zepto.isZ(value) ? value.toArray() : value
}
// 檢測當前調用 concat函數的對象是不是 zepto 對象,如果是那麼先轉化成數組再與args拼接,否則直接與args拼接。返回拼接結果
return concat.apply(zepto.isZ(this) ? this.toArray() : this, args)
},
map
遍歷對象集合中的所有元素。通過遍歷函數返回值形成一個新的集合對象。
map: function(fn){
// 先調用 $.map 方法,把對象中的數據全用 fn 處理一遍,生成一個數組。再將數組中的內容通過 $() 方法轉化成 zepto 對象。
return $($.map(this, function(el, i){ return fn.call(el, i, el) }))
},
slice
提取這個數組array的子集,從start開始,如果給定end,提取從從start開始到end結束的元素,但是不包含end位置的元素。
slice: function(){
// 調用 slice 方法,截取該數組,並轉化成 zepto 對象
return $(slice.apply(this, arguments))
},
ready
ready: function(callback){
// 通過檢測 document.readyState 來判斷頁面是否加載成功,
// doScroll 是用於檢測 IE 瀏覽器加載狀態的
// 如果頁面加載成功,那麼立即將回調函數放在執行隊形中
if (document.readyState === "complete" ||
(document.readyState !== "loading" && !document.documentElement.doScroll))
setTimeout(function(){ callback($) }, 0)
else {
// 添加事件監聽,如果監聽到 DOMContented 或者 load 事件,那麼就表明頁面執行完成,執行 handler
var handler = function() {
document.removeEventListener("DOMContentLoaded", handler, false)
window.removeEventListener("load", handler, false)
callback($)
}
document.addEventListener("DOMContentLoaded", handler, false)
window.addEventListener("load", handler, false)
}
return this
},
size
獲取對象集合中元素的數量。
size: function(){
return this.length
},
each
遍歷一個對象集合每個元素。如果迭代函數返回 false,遍歷結束。
// emptyArray 的定義在頂部數據定義部分
emptyArray = []
each: function(callback){
// 使用 Array.prototype.every 然後監測返回值,就可以做到當迭代函數返回 false 時,遍歷結束
emptyArray.every.call(this, function(el, idx){
return callback.call(el, idx, el) !== false
})
return this
},
remove
從其父節點中刪除當前集合中的元素,有效的從dom中移除。
remove: function(){
// 本函數本質上是返回 this 。即當前操作的 zepto 對象。這樣做的好處是可以鏈式調用
return this.each(function(){
// 遍歷當前操作的 zepto 對象。如果其存在父元素,那麼就將其從父元素中移除
if (this.parentNode != null)
this.parentNode.removeChild(this)
})
},
not
過濾當前對象集合,獲取一個新的對象集合,它裏面的元素不能匹配css選擇器。如果另一個參數爲Zepto對象集合,那麼返回的新Zepto對象中的元素都不包含在該參數對象中。如果參數是一個函數。僅僅包含函數執行爲false值得時候的元素,函數的 this 關鍵字指向當前循環元素。
not: function(selector){
var nodes=[]
// 如果傳入內容是一個函數,且函數存在call方法
if (isFunction(selector) && selector.call !== undefined)
// 對當前指向的DOM數組執行 each 方法,如果返回值爲false,傳到到nodes數組中
this.each(function(idx){
if (!selector.call(this,idx)) nodes.push(this)
})
else {
// 當 selector 爲字符串時,對數組進行篩選,找出滿足selector的內容
// 當 selector 爲 nodeList 時執行 slice.call(selector) ,這裏的isFunction(selector.item)是爲了排除selector爲數組的情況
//當selector爲css選擇器,執行$(selector)
var excludes = typeof selector == 'string' ? this.filter(selector) :
(likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector)
//篩選出不在 excludes 數組中的記錄,達到除去的目的
this.forEach(function(el){
if (excludes.indexOf(el) < 0) nodes.push(el)
})
}
// 將nodes數組轉化成 zepto 對象並返回
return $(nodes)
},
filter
過濾對象集合,返回對象集合中滿足css選擇器的項。如果參數爲一個函數,函數返回有實際值得時候,元素纔會被返回。
filter: function(selector){
// 如果傳入內容是個函數,那麼返回 兩次not函數篩選的結果,負負爲正
if (isFunction(selector)) return this.not(this.not(selector))
// 如果傳入的是一個css選擇器,那麼執行 matches 來篩選,並將結果轉化成一個 zepto 數組
return $(filter.call(this, function(element){
return zepto.matches(element, selector)
}))
},
關於 matches 函數,我在上面文章 Zepto源碼二之工具函數中提到過,在此略過
add
添加元素到當前匹配的元素集合中。如果給定content參數,將只在content元素中進行查找,否則在整個document中查找。
add: function(selector,context){
// 先調用 $ 函數,將 selector轉化成zepto對象,再拼接到現在操作的 zepto 對象上,再去重,將去重結果再轉化成zepto對象並返回
return $(uniq(this.concat($(selector,context))))
},
is
判斷當前元素集合中的第一個元素是否符css選擇器。對於基礎支持jquery的非標準選擇器類似: :visible包含在可選的“selector”模塊中。
is: function(selector){
// 先判斷傳入的是不是css選擇器(通常是string形字符串)
// 如果當前操作的 zepto 對象存在,且有內容,那麼用 matches 匹配傳入的內容是不是第一個,如果是 返回 true,否則返回 false
return typeof selector == 'string' ? this.length > 0 && zepto.matches(this[0], selector) :
// 如果不存在則尷尬了,只能強行檢驗傳入的selector與當前對象的selector是不是相等,返回比較結果
selector && this.selector == selector.selector
},
find
在當對象前集合內查找符合CSS選擇器的每個元素的後代元素。如果給定Zepto對象集合或者元素,過濾它們,只有當它們在當前Zepto集合對象中時,纔回被返回。
find: function(selector){
var result, $this = this
// 如果沒有傳入選擇器,返回一個包含空值 zepto 對象
if (!selector) result = $()
else if (typeof selector == 'object')
// 如果選擇器是一個對象
result = $(selector).filter(function(){
var node = this
// //如果 $.contains 返回 true ,則 emptyArray.some 也會返回true,外層的filter則會收錄該條記錄
return emptyArray.some.call($this, function(parent){
return $.contains(parent, node)
})
})
// 如果selector是css選擇器
// 如果當前集合長度爲1時,調用zepto.qsa,將結果轉成zepto對象
else if (this.length == 1) result = $(zepto.qsa(this[0], selector))
// 如果長度大於1,則調用map遍歷
else result = this.map(function(){ return zepto.qsa(this, selector) })
// 返回結果
return result
},
has
判斷當前對象集合的子元素是否有符合選擇器的元素,或者是否包含指定的DOM節點,如果有,則返回新的對象集合,該對象過濾掉不含有選擇器匹配元素或者不含有指定DOM節點的對象。
has: function(selector){
return this.filter(function(){
return isObject(selector) ?
$.contains(this, selector) :
$(this).find(selector).size()
})
},
// 這一段可以這麼改寫以便於理解
changeHas: funcion(selector){
var nodes
// 如果傳入內容是一個對象,那麼直接使用 $.contains 來檢測,否則用 find 來查找
if(isObject(selector)){
nodes = $.contains(this, selector)
} else {
nodes = $(this).find(selector).size()
}
// 返回查找結果用 filter 篩選後的結果
return this.filter(nodes)
}
eq
從當前對象集合中獲取給定索引值的元素。
eq: function(idx){
// + idx +1 是隱式類型轉換,確定idx是一個數字
return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1)
},
first
獲取當前對象集合中的第一個元素。
first: function(){
var el = this[0]
// 如果 el 存在,那麼將它轉化成 zepto 對象傳回
return el && !isObject(el) ? el : $(el)
},
last
獲取當前對象集合中的最後一個元素。
last: function(){
var el = this[this.length - 1]
return el && !isObject(el) ? el : $(el)
},
closest
從元素本身開始,逐級向上級元素匹配,並返回最先匹配selector的元素。如果給定context節點參數,那麼只匹配該節點的後代元素。這個方法與 parents(selector)有點相像,但它只返回最先匹配的祖先元素。
如果參數是一個Zepto對象集合或者一個元素,結果必須匹配給定的元素而不是選擇器。
closest: function(selector, context){
// 判斷 selector 是不是一個對象如果是那麼轉化成一個 zepto 對象並賦值給 collection ,如果不是那麼將 collection 賦值爲 false
var nodes = [], collection = typeof selector == 'object' && $(selector)
this.each(function(_, node){
// 當selector是字符串選擇器時,如果node與selector不匹配,則需要取node.parentNode進行判斷
// 當node 不是context,document的時候,取node.parentNode
while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector)))
node = node !== context && !isDocument(node) && node.parentNode
if (node && nodes.indexOf(node) < 0) nodes.push(node)
})
// 將結果轉換成一個 zepto 對象
return $(nodes)
},
parents
獲取對象集合每個元素所有的祖先元素。如果css選擇器參數給出,過濾出符合條件的元素。
parents: function(selector){
var ancestors = [], nodes = this
while (nodes.length > 0)
nodes = $.map(nodes, function(node){
// 當selector是字符串選擇器時,如果node與selector不匹配,則需要取node.parentNode進行判斷
// 當node 不是context,document的時候,取node.parentNode
if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) {
ancestors.push(node)
return node
}
})
return filtered(ancestors, selector)
},
pluck
獲取對象集合中每一個元素的屬性值。返回值爲 null或undefined值得過濾掉。
pluck: function(property){
return $.map(this, function(el){ return el[property] })
},
parent
獲取對象集合中每個元素的直接父元素。如果css選擇器參數給出。過濾出符合條件的元素。
parent: function(selector){
// 找出直接父元素,再過濾重複值篩選一下,返回結果
return filtered(uniq(this.pluck('parentNode')), selector)
},
children
獲得每個匹配元素集合元素的直接子元素,如果給定selector,那麼返回的結果中只包含符合css選擇器的元素。
// 得到element元素的子元素(nodeType === 1)集合
// 如果element支持children屬性則直接返回
// 反則遍歷子節點中nodeType爲1的節點(即元素節點)
children: function(selector){
return filtered(this.map(function(){ return children(this) }), selector)
},
contents
獲得每個匹配元素集合元素的子元素,包括文字和註釋節點。
contents: function() {
return this.map(function() { return this.contentDocument || slice.call(this.childNodes) })
},
siblings
獲取對象集合中所有元素的兄弟節點。如果給定CSS選擇器參數,過濾出符合選擇器的元素。
// 先獲取當前元素的父節點,然後獲取該父節點的所有子節點
// 再從所有子節點中去掉當前元素
// 最後如果傳了selector,再將所有的子節點過濾出符合selector條件的
siblings: function(selector){
return filtered(this.map(function(i, el){
return filter.call(children(el.parentNode), function(child){ return child!==el })
}), selector)
},
empty
清空對象集合中每個元素的DOM內容。
empty: function(){
return this.each(function(){ this.innerHTML = '' })
},
show
恢復對象集合中每個元素默認的“display”值。如果你用 hide將元素隱藏,用該屬性可以將其顯示。相當於去掉了display:none。
show: function(){
return this.each(function(){
this.style.display == "none" && (this.style.display = '')
// 通過 getComputedStyle 來查看當前元素計算後的樣式,如果 display 爲 none 。那麼將其 display 設置成默認
if (getComputedStyle(this, '').getPropertyValue("display") == "none")
this.style.display = defaultDisplay(this.nodeName)
})
},
replaceWith
用給定的內容替換所有匹配的元素。(包含元素本身)。content參數可以爲 before中描述的類型。
replaceWith: function(newContent){
// 在該節點前面插入新的內容,然後刪除該節點,以達到替換的目的
return this.before(newContent).remove()
},
wrap
在每個匹配的元素外層包上一個html元素。structure參數可以是一個單獨的元素或者一些嵌套的元素。也可以是一個html字符串片段或者dom節點。還可以是一個生成用來包元素的回調函數,這個函數返回前兩種類型的包裹片段。
wrap: function(structure){
var func = isFunction(structure)
// 當前操作的 zepto 對象不爲空且 structure 不爲函數
if (this[0] && !func)
// 將 structure 的第一個元素賦值給 dom
// 如果dom元素的parentNode存在或者當前選中的元素個人大於1那麼clone爲true
var dom = $(structure).get(0),
clone = dom.parentNode || this.length > 1
return this.each(function(index){
// 如果structure爲函數,則將當前的元素和對應的索引傳入函數
$(this).wrapAll(
func ? structure.call(this, index) :
clone ? dom.cloneNode(true) : dom
)
})
},
wrapAll
在所有匹配元素外面包一個單獨的結構。結構可以是單個元素或 幾個嵌套的元素,並且可以通過在作爲HTML字符串或DOM節點。
wrapAll: function(structure){
if (this[0]) {
// 如果當前操作的 zepto 對象存在
// 在當前操作的 zepto 對象前面插入被轉化成 zepto 對象的 structure 對象
$(this[0]).before(structure = $(structure))
var children
// 獲取structure的最深層次的第一個子元素
// 將當前的元素集合通過append方法添加到structure末尾
while ((children = structure.children()).length) structure = children.first()
$(structure).append(this)
}
return this
},
wrapInner
將每個元素中的內容包裹在一個單獨的結構中。結構可以是單個元件或多個嵌套元件,並且可以通過在作爲HTML字符串或DOM節點,或者是一個生成用來包元素的回調函數,這個函數返回前兩種類型的包裹片段。
wrapInner: function(structure){
var func = isFunction(structure)
return this.each(function(index){
var self = $(this), contents = self.contents(),
// contents => 獲取當前元素的所有子節點(包括元素節點和文本節點)
// structure爲函數則將其執行結果賦值爲dom,否則直接將其賦值
// 當前元素的子節點不爲空,則調用wrapAll,否則直接將dom插入self當前元素即可
dom = func ? structure.call(this, index) : structure
contents.length ? contents.wrapAll(dom) : self.append(dom)
})
},
unwrap
移除集合中每個元素的直接父節點,並把他們的子元素保留在原來的位置。 基本上,這種方法刪除上一的祖先元素,同時保持DOM中的當前元素。
unwrap: function(){
// 通過parent()獲取當前元素集合的所有直接父節點
// 將獲取到的父節點集合進行遍歷
// 將該父節點替換爲該父節點的所有子節點
this.parent().each(function(){
$(this).replaceWith($(this).children())
})
return this
},
clone
通過深度克隆來複制集合中的所有元素。
// 將當前元素賦值一份,用了cloneNode這個原生方法,並且傳了true
clone: function(){
return this.map(function(){ return this.cloneNode(true) })
},
hide
通過設置css的屬性display 爲 none來將對象集合中的元素隱藏。
hide: function(){
return this.css("display", "none")
},
toggle
顯示或隱藏匹配元素。如果 setting爲true,相當於show 法。如果setting爲false。相當於 hide方法。
toggle: function(setting){
return this.each(function(){
var el = $(this)
// 先判斷有沒有傳入 setting 如果設置了,則使用 setting 的規則來進行設置
// 如果沒有設置 setting ,那麼通過元素的 display 判斷來進行設置顯示或者隱藏
;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide()
})
},
prev
獲取對象集合中每一個元素的前一個兄弟節點,通過選擇器來進行過濾。
prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') },
next
獲取對象集合中每一個元素的下一個兄弟節點(可以選擇性的帶上過濾選擇器)。
next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') },
html
獲取或設置對象集合中元素的HTML內容。當沒有給定content參數時,返回對象集合中第一個元素的innerHtml。當給定content參數時,用其替換對象集合中每個元素的內容。content可以是append中描述的所有類型。
html: function(html){
return 0 in arguments ?
this.each(function(idx){
var originHtml = this.innerHTML
$(this).empty().append( funcArg(this, html, idx, originHtml) )
}) :
(0 in this ? this[0].innerHTML : null)
},
// 簡單的改寫一下
html: function(html) {
// 沒有傳入參數,那麼直接獲取第一個元素的html內容
if(html === undefined){
if(this[0]){
// 第一個元素存在就返回內容
return this[0].innerHTML
} else {
// 不存在就返回 null
return null
}
} else {
return this.each(function(idx){
var originHtml = this.innerHTML
$(this).empty().append( funcArg(this, html, idx, originHtml) )
})
}
}
text
獲取或者設置所有對象集合中元素的文本內容。當沒有給定content參數時,返回當前對象集合中第一個元素的文本內容(包含子節點中的文本內容)。當給定content參數時,使用它替換對象集合中所有元素的文本內容。它有待點似 html,與它不同的是它不能用來獲取或設置 HTML。
text: function(text){
return 0 in arguments ?
this.each(function(idx){
var newText = funcArg(this, text, idx, this.textContent)
this.textContent = newText == null ? '' : ''+newText
}) :
(0 in this ? this.pluck('textContent').join("") : null)
},
attr
讀取或設置dom的屬性。如果沒有給定value參數,則讀取對象集合中第一個元素的屬性值。當給定了value參數。則設置對象集合中所有元素的該屬性的值。當value參數爲null,那麼這個屬性將被移除(類似removeAttr),多個屬性可以通過對象鍵值對的方式進行設置。
attr: function(name, value){
var result
return (typeof name == 'string' && !(1 in arguments)) ?
// 獲取屬性
(0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null ? result : undefined) :
// 設置屬性
this.each(function(idx){
if (this.nodeType !== 1) return
// 設置多個屬性值
if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
// 設置一個屬性值
else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
})
},
removeAttr
移除當前對象集合中所有元素的指定屬性。
removeAttr: function(name){
return this.each(function(){ this.nodeType === 1 && name.split(' ').forEach(function(attribute){
setAttribute(this, attribute)
}, this)})
},
prop
讀取或設置dom元素的屬性值。它在讀取屬性值的情況下優先於 attr,因爲這些屬性值會因爲用戶的交互發生改變,如checked 和 selected。
簡寫或小寫名稱,比如for, class, readonly及類似的屬性,將被映射到實際的屬性上,比如htmlFor, className, readOnly, 等等。
prop: function(name, value){
name = propMap[name] || name
return (typeof name == 'string' && !(1 in arguments)) ?
(this[0] && this[0][name]) :
this.each(function(idx){
if (isObject(name)) for (key in name) this[propMap[key] || key] = name[key]
else this[name] = funcArg(this, value, idx, this[name])
})
},
removeProp
從集合的每個DOM節點中刪除一個屬性。這是用JavaScript的delete操作符完成。值得注意的是如果嘗試刪除DOM的一些內置屬性,如className或maxLength,將不會有任何效果,因爲瀏覽器禁止刪除這些屬性。
removeProp: function(name){
name = propMap[name] || name
return this.each(function(){ delete this[name] })
},
data
讀取或寫入dom的 data-* 屬性。行爲有點像 attr ,但是屬性名稱前面加上 data-。
data: function(name, value){
var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase()
var data = (1 in arguments) ?
this.attr(attrName, value) :
this.attr(attrName)
return data !== null ? deserializeValue(data) : undefined
},
val
獲取或設置匹配元素的值。當沒有給定value參數,返回第一個元素的值。如果是標籤,則返回一個數組。當給定value參數,那麼將設置所有元素的值。
val: function(value){
if (0 in arguments) {
if (value == null) value = ""
return this.each(function(idx){
this.value = funcArg(this, value, idx, this.value)
})
} else {
return this[0] && (this[0].multiple ?
$(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') :
this[0].value)
}
},
offset
獲得當前元素相對於document的位置。返回一個對象含有: top, left, width和height
當給定一個含有left和top屬性對象時,使用這些值來對集合中每一個元素進行相對於document的定位。
offset: function(coordinates){
if (coordinates) return this.each(function(index){
var $this = $(this),
coords = funcArg(this, coordinates, index, $this.offset()),
parentOffset = $this.offsetParent().offset(),
props = {
top: coords.top - parentOffset.top,
left: coords.left - parentOffset.left
}
if ($this.css('position') == 'static') props['position'] = 'relative'
$this.css(props)
})
if (!this.length) return null
if (document.documentElement !== this[0] && !$.contains(document.documentElement, this[0]))
return {top: 0, left: 0}
var obj = this[0].getBoundingClientRect()
return {
left: obj.left + window.pageXOffset,
top: obj.top + window.pageYOffset,
width: Math.round(obj.width),
height: Math.round(obj.height)
}
},
css
讀取或設置DOM元素的css屬性。當value參數不存在的時候,返回對象集合中第一個元素的css屬性。當value參數存在時,設置對象集合中每一個元素的對應css屬性。
多個屬性可以通過傳遞一個屬性名組成的數組一次性獲取。多個屬性可以利用對象鍵值對的方式進行設置。
當value爲空(空字符串,null 或 undefined),那個css屬性將會被移出。當value參數爲一個無單位的數字,如果該css屬性需要單位,“px”將會自動添加到該屬性上。
css: function(property, value){
// 如果參數小於2,那麼是取值操作
if (arguments.length < 2) {
var element = this[0]
if (typeof property == 'string') {
// 如果傳入是一個字符串,那就說明是取一個單獨的css樣式,返回結果
if (!element) return
return element.style[camelize(property)] || getComputedStyle(element, '').getPropertyValue(property)
} else if (isArray(property)) {
// 如果傳入的是一個數組,那麼返回一個對象,對象內容是數組所列的屬性與其對應值的鍵值對
if (!element) return
var props = {}
var computedStyle = getComputedStyle(element, '')
$.each(property, function(_, prop){
props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop))
})
return props
}
}
var css = ''
if (type(property) == 'string') {
if (!value && value !== 0)
this.each(function(){ this.style.removeProperty(dasherize(property)) })
else
css = dasherize(property) + ":" + maybeAddPx(property, value)
} else {
for (key in property)
if (!property[key] && property[key] !== 0)
this.each(function(){ this.style.removeProperty(dasherize(key)) })
else
css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';'
}
return this.each(function(){ this.style.cssText += ';' + css })
},
index
獲取一個元素的索引值。當elemen參數沒有給出時,返回當前元素在兄弟節點中的位置。當element參數給出時,返回它在當前對象集合中的位置。如果沒有找到該元素,則返回-1。
index: function(element){
return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0])
},
hasClass
檢查對象集合中是否有元素含有指定的class。
hasClass: function(name){
if (!name) return false
return emptyArray.some.call(this, function(el){
return this.test(className(el))
}, classRE(name))
},
addClass
爲每個匹配的元素添加指定的class類名。多個class類名使用空格分隔。
addClass: function(name){
if (!name) return this
return this.each(function(idx){
if (!('className' in this)) return
classList = []
// 獲取當前元素的className,以及通過funcArg包裝參數,這樣name既可以是字符串也可以是回調函數
var cls = className(this), newName = funcArg(this, name, idx, cls)
// 對要設置的class newName進行分割後遍歷處理
newName.split(/\s+/g).forEach(function(klass){
// 當前元素不存在要添加的class的時候才往classList中push
if (!$(this).hasClass(klass)) classList.push(klass)
}, this)
// 首先檢查classList的長度,如果長度爲0就沒有必要設置了,然後調用className函數進行class設置
classList.length && className(this, cls + (cls ? " " : "") + classList.join(" "))
})
},
removeClass
移除當前對象集合中所有元素的指定class。如果沒有指定name參數,將移出所有的class。多個class參數名稱可以利用空格分隔。
removeClass: function(name){
return this.each(function(idx){
if (!('className' in this)) return
if (name === undefined) return className(this, '')
classList = className(this)
funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){
// 將匹配中的klass替換成' ',從而起到刪除的作用
classList = classList.replace(classRE(klass), " ")
})
className(this, classList.trim())
})
},
toggleClass
在匹配的元素集合中的每個元素上添加或刪除一個或多個樣式類。如果class的名稱存在則刪除它,如果不存在,就添加它。如果 setting的值爲真,這個功能類似於 addClass,如果爲假,這個功能類似與 removeClass。
toggleClass: function(name, when){
if (!name) return this
return this.each(function(idx){
// name 可以是字符串也可以是函數
var $this = $(this), names = funcArg(this, name, idx, className(this))
// 因爲有可能是切換多個class,所以切割之後遍歷處理
names.split(/\s+/g).forEach(function(klass){
// 當when沒有傳入的時候,進行的邏輯是元素有kClass,就移除,否則添加
// 當指定了when轉換後爲真便是添加,否則移除kClass
(when === undefined ? !$this.hasClass(klass) : when) ?
$this.addClass(klass) : $this.removeClass(klass)
})
})
},
scrollTop
獲取或設置頁面上的滾動元素或者整個窗口向下滾動的像素值。
scrollTop: function(value){
if (!this.length) return
// 當前元素是否有scrollTop屬性
var hasScrollTop = 'scrollTop' in this[0]
// 如果沒有傳入value值,則是取值操作,hasScrollTop爲真則返回元素的scrollTop屬性值,否則返回元素的pageYOffset屬性值
if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset
return this.each(hasScrollTop ?
// 如果有scrollTop屬性則直接設置該屬性對應的value值
function(){ this.scrollTop = value } :
// 否則調用元素的scrollTo方法,並傳入scrollX和value
function(){ this.scrollTo(this.scrollX, value) })
},
scrollLeft
獲取或設置頁面上的滾動元素或者整個窗口向右滾動的像素值。
scrollLeft: function(value){
if (!this.length) return
var hasScrollLeft = 'scrollLeft' in this[0]
if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset
return this.each(hasScrollLeft ?
function(){ this.scrollLeft = value } :
function(){ this.scrollTo(value, this.scrollY) })
},
offsetParent
找到第一個定位過的祖先元素,意味着它的css中的position 屬性值爲“relative”, “absolute” or “fixed”
rootNodeRE = /^(?:body|html)$/i,
offsetParent: function() {
return this.map(function(){
// 獲取集合中當前元素的有定位元素的最近的祖先元素,沒有獲取到則用body元素賦值
var parent = this.offsetParent || document.body
// 祖先元素存在,並且不是根元素,html或者body元素,並且parent的position屬性爲static則再次進入循環
// 以上條件都不滿足則直接返回parent元素
while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static")
parent = parent.offsetParent
return parent
})
}
position
獲取對象集合中第一個元素的位置。相對於 offsetParent。當絕對定位的一個元素靠近另一個元素的時候,這個方法是有用的。
position: function() {
if (!this.length) return
var elem = this[0],
// 找到有定位屬性的祖先元素
offsetParent = this.offsetParent(),
// 獲取當前元素相對於document的位置
offset = this.offset(),
// 獲取父元素相對於document的位置,如果是根元素(html或者body)則爲0, 0
parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset()
// 相對於第一個定位祖先元素的位置關係不應該包括margin的舉例,所以減去
offset.top -= parseFloat( $(elem).css('margin-top') ) || 0
offset.left -= parseFloat( $(elem).css('margin-left') ) || 0
// 祖先定位元素加上border的寬度
parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0
parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0
// 計算結果
return {
top: offset.top - parentOffset.top,
left: offset.left - parentOffset.left
}
},
detach
$.fn.detach = $.fn.remove
forEach
forEach: emptyArray.forEach,
reduce
reduce: emptyArray.reduce,
push
push: emptyArray.push,
sort
sort: emptyArray.sort,
splice
splice: emptyArray.splice,
indexOf
在當前對象集合中獲取一個元素的索引值。如果給定formindex參數,從該位置開始往後查找,返回基於0的索引值,如果沒找到,則返回-1。index 方法是基於這個方法實現的。
indexOf: emptyArray.indexOf,