平時工作中褒傅,相信很多小伙伴跟我一樣捧存,jquery的index()方法用的很多粪躬,也用得很爽,一直都覺得不可思議昔穴。今天就偶然想了解一下它的實現原理镰官,便翻起了jquery的源碼,窺得了它大致的實現原理吗货。
場景重現:(jquery自行引入)
html:
<ul id="test">
<li id="t1">1</li>
<li id="t2">2</li>
<li id="t3">3</li>
</ul>
js:
$("#test").on('click', 'li', function(e) {
console.log($(this).index());
})
就如此小的一個demo泳唠,引發(fā)了我對index()方法的種種聯想,為什么點擊當前的元素可以知道它的索引呢宙搬?難道要預先知道它的父級嗎笨腥,這不可能,這些dom節(jié)點又不是固定的勇垛,那到底脖母。。闲孤。谆级。。崭放。
下面就開啟源碼之旅吧哨苛。
首先是index()方法鸽凶,其源碼如下:
index: function( elem ) {
// No argument, return index in parent
if ( !elem ) {
return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
}
// Index in selector
if ( typeof elem === "string" ) {
return indexOf.call( jQuery( elem ), this[ 0 ] );
}
// Locate the position of the desired element
return indexOf.call( this,
// If it receives a jQuery object, the first element is used
elem.jquery ? elem[ 0 ] : elem
);
}
源碼很精簡币砂,而且我們只想看沒傳參時的index方法的用法,所以只看這句:
if ( !elem ) {
return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
}
其實這句的重點在prevAll方法玻侥,其它都是些使邏輯嚴謹的代碼决摧,因此我們側重點放在prevAll方法。所以,翻看了prevAll方法:
jQuery.each({
// ...此處省略了很多非相關代碼
prevAll: function( elem ) {
return dir( elem, "previousSibling" );
},
}, function(name, fn) { // ...省略 })
緊接著掌桩,我們看dir源碼:
function dir( elem, dir, until ) {
var matched = [],
truncate = until !== undefined;
while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
if ( elem.nodeType === 1 ) {
if ( truncate && jQuery( elem ).is( until ) ) {
break;
}
matched.push( elem );
}
}
return matched;
}
看到這里边锁,其實大致思路已經知道了:遍歷查找當前元素的上一個同級元素,形成一個包含所有該元素的前面的元素的集合波岛∶┨常可能有點拗口,回到我們的小demo则拷,在控制臺模擬一下prevAll的過程贡蓖,看著以下截圖應該好理解些:
而dir函數已經為我們過濾了文本節(jié)點:
if ( elem.nodeType === 1 )
最終就是返回一個所有的前面元素的集合給我們了,然后index就是prevAll().length(該集合的長度)了煌茬。
ps: 可能細心的小伙伴會發(fā)現有漏洞斥铺,index源碼上是這樣的:
if ( !elem ) {
return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
}
人家的prevAll明明沒傳參數,那按道理prevAll就接收不到elem參數坛善,則elem為undefined晾蜘,那就沒有后續(xù)的故事情節(jié)了。關于這個眠屎,我只想說剔交,你知道得太多了。组力。省容。。燎字。腥椒。
由于本人精力有限,所以只能猜想是jQuery.each方法做了手腳候衍,使得不傳參的prevAll里面的elem自動變?yōu)閠his對象笼蛛。(當然這只是本人猜想),希望有知道的留言一下蛉鹿,共勉滨砍,謝謝大家。