jQuery方法解析(一)append
接下來幾天俺會讓俺媳婦隨機挑幾個jq的函式方法,然後我檢視原始碼,以及加入自己的理解寫幾個博文,如果大家有特別希望瞭解的可以回覆,這樣我就不用讓俺媳婦挑了。
今天以及接下來幾天的jq均已jq1.7.1這個版本為例。
首先我們來看下jqapi的說明:向每個匹配的元素內部追加內容。
這個操作與對指定的元素執行appendChild方法,將它們新增到文件中的情況類似。
這個方法接收1個引數:content,接受型別有4種(3種從1.0就有了,function從1.4之後開始有)
String:字串,這個容易理解就是可以直接$("選擇器").append("aaaabbbbbcccc");這麼寫,當然jq內部還支援$("選擇器").append('<a href="#"></a>');這種html標籤的字串,至於效能方面咋們後面看原始碼的時候在細論。
Element:節點,這個也容易理解就是dom節點麼基本上俺是寫成,$("選擇器").append(document.getElementsByTagName("a"))這類,不過這麼寫的同學要注意一點,這麼寫會將原來位置的dom給“剪下”到選擇器底部,請允許我這麼形容。
jQuery:jQuery物件,這注意這個物件是jq選擇器加工過的物件,比如$("選擇器1").append($(“選擇器2”));而不是$("選擇器1").append($);寫到這俺笑了,應該沒人寫append($)這個是吧。
function(index, html):一個function物件(引數後面講),可以寫成$("選擇器").append(function(index,html){return ""});其中return "" 可以省略,任何函式都有返回值,沒寫return就會返回undefined
var _body=$("body");
_body.html('');//清空body
_body.append("<div></div><div></div>");//插入2個空div
$("div").append(function(){return "a"});//我們要用結果猜個答案,雖然不是必須用這個例子,不過反正到這了 就這麼寫了
看到結果,俺猜append方法內部對整個選擇器進行了遍歷,然後插入了函式返回的東西。
所以index和html很容易理解了,就是在便利過程中的index和index對應的原先的html(插入之前);
最後講一下,就是jq本身就是鏈式呼叫,所以append()返回的是選擇器選擇的物件被插之後的新物件,講的好邪惡。
可以$("選擇器").append().append().append().......................,不過一般都不會這麼玩吧?
解釋完API我們來看看原始碼
看到這個截圖...好吧我們繼續往下看。
domManip: function (args, table, callback) {
//定義6個變數,我們先不管這些變數幹嘛。
var results, first, fragment, parent,
value = args[0],/*args引數在append呼叫的時候其實只有1個引數*/
scripts = [];
/*
進行了各種判斷
1、!jQuery.support.checkClone:確保文件碎片還沒有被克隆(作用在後面)
2、arguments.length === 3,確保呼叫domManip這個函式只有3個引數,否則會往後面走,這個很妙
3、typeof value === "string"確認你的引數是string型別
4、rchecked.test(value)
*/
if (!jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test(value)) {
//遍歷選擇器,看來我前面的猜測對了
return this.each(function () {
//看每次迴圈都呼叫了這個domManip,但是這些呼叫不會進入這個if,為什麼?仔細看上面的註釋與下面的呼叫
jQuery(this).domManip(args, table, callback, true);
});
}
//如果引數型別是function的
if (jQuery.isFunction(value)) {
//還是遍歷
return this.each(function (i) {
var self = jQuery(this);
/*
記得function的返回值嗎?這邊就把那邊的返回值存到args[0]裡面了
table ? self.html() : undefined;這句話看不懂?table這個變數,在append呼叫domManip時已經寫死了是true
所以在執行function型別引數的時候那個index和html是什麼這邊已經很明顯了
*/
args[0] = value.call(this, i, table ? self.html() : undefined);
//取到插入的內容之後,重複第一步......
self.domManip(args, table, callback);
});
}
/*
到了這裡,已經確保你取到了function中返回的string
上面的各種判斷已經把你引數處理成接下去想要的,淡定的往下看吧
if (this[0]) 這個判斷。。。確保選擇器存在,為什麼不放最前面?
*/
if (this[0]) {
/*
取父級節點
&&運算子就是
0&&1=0
1&&2=2
0&&0=0
*/
parent = value && value.parentNode;
// If we're in a fragment, just use that instead of building a new one
/*
如果已經有元素碎片了就用原來的,不然就新建一個
*/
if (jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length) {
results = { fragment: parent };
} else {
results = jQuery.buildFragment(args, this, scripts);
}
fragment = results.fragment;
//取碎片中最後一個
if (fragment.childNodes.length === 1) {
first = fragment = fragment.firstChild;
} else {
first = fragment.firstChild;
}
//存在最後一個節點
if (first) {
//確保最後一個元素是tr?
table = table && jQuery.nodeName(first, "tr");
for (var i = 0, l = this.length, lastIndex = l - 1; i < l; i++) {
callback.call(
table ?
root(this[i], first) :
this[i],
// Make sure that we do not leak memory by inadvertently discarding
// the original fragment (which might have attached data) instead of
// using it; in addition, use the original fragment object for the last
// item instead of first because it can end up being emptied incorrectly
// in certain situations (Bug #8070).
// Fragments from the fragment cache must always be cloned and never used
// in place.
results.cacheable || (l > 1 && i < lastIndex) ?
jQuery.clone(fragment, true, true) :
fragment
);
}
}
/*插入指令碼檔案的話jq會幫你去請求的*/
if (scripts.length) {
jQuery.each(scripts, function (i, elem) {
if (elem.src) {
jQuery.ajax({
type: "GET",
global: false,
url: elem.src,
async: false,
dataType: "script"
});
} else {
jQuery.globalEval((elem.text || elem.textContent || elem.innerHTML || "").replace(rcleanScript, "/*$0*/"));
}
if (elem.parentNode) {
elem.parentNode.removeChild(elem);
}
});
}
}
return this;
}
在往裡面還有個底層buildFragment方法,我稍微看了,解釋起來頗為費勁。
底層程式碼解釋起來麻煩俺就直接註釋到原始碼裡面去了,大家瞅瞅 有木有不對的,求斧正,另外大家可以加俺的QQ群:43881427一起討論討論前端問題
裡面還有.net SQL的高手哦