1. 程式人生 > >jQuery方法解析(一)append

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

,這個貌似高程或者權威指南有講,具體哪寫的,俺也忘記了。index引數為物件在這個集合中的索引值,要解釋這句話,我們看個例子吧

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的高手哦