domManip 這個函數的歷史由來已久,從 jQuery 1.0 版本開始便存在了,一直到最新的 jQuery 版本。可謂是元老級工具函數。 domManip 的主要功能是為了實現 DOM 的插入和替換。具體共為以下 5 個函數服務 內部後插入(append) 內部前插入(prepend) 外部前 ...
domManip 這個函數的歷史由來已久,從 jQuery 1.0 版本開始便存在了,一直到最新的 jQuery 版本。可謂是元老級工具函數。
domManip 的主要功能是為了實現 DOM 的插入和替換。具體共為以下 5 個函數服務
- 內部後插入(append)
- 內部前插入(prepend)
- 外部前插入(before)
- 外部後插入(after)
- 替換元素 (replaceWith,1.9.x 之前的版本沒有使用 domMainp)
而一個 each 就生成了另外 5 個函數:appendTo、prependTo、insertBefore、insertAfter、replaceAll
jQuery.each( { appendTo: "append", prependTo: "prepend", insertBefore: "before", insertAfter: "after", replaceAll: "replaceWith" }, function( name, original ) { jQuery.fn[ name ] = function( selector ) { var elems, ret = [], insert = jQuery( selector ), last = insert.length - 1, i = 0; for ( ; i <= last; i++ ) { elems = i === last ? this : this.clone( true ); jQuery( insert[ i ] )[ original ]( elems ); // Support: Android <=4.0 only, PhantomJS 1 only // .get() because push.apply(_, arraylike) throws on ancient WebKit push.apply( ret, elems.get() ); } return this.pushStack( ret ); }; } );
如圖
內部調用如圖
源碼
append: function() { return domManip( this, arguments, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { var target = manipulationTarget( this, elem ); target.appendChild( elem ); } } ); }, prepend: function() { return domManip( this, arguments, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { var target = manipulationTarget( this, elem ); target.insertBefore( elem, target.firstChild ); } } ); }, before: function() { return domManip( this, arguments, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this ); } } ); }, after: function() { return domManip( this, arguments, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this.nextSibling ); } } ); }, replaceWith: function() { var ignored = []; // Make the changes, replacing each non-ignored context element with the new content return domManip( this, arguments, function( elem ) { var parent = this.parentNode; if ( jQuery.inArray( this, ignored ) < 0 ) { jQuery.cleanData( getAll( this ) ); if ( parent ) { parent.replaceChild( elem, this ); } } // Force callback invocation }, ignored ); }
domManip 的實現
domManip 的主要功能就是添加 DOM 元素,因為添加的位置不同而提供了四個公開函數 append、prepend、before、after,此外還有一個 replaceWith。簡單說 domManip 就做了兩件事
- 先完成 DOM 節點添加
- 如果添加的 DOM 節點內有 script 標簽,需要額外處理下。對於可執行的 script (通過type屬性判斷)則執行其內的腳本代碼,其它的則不執行。
domManip 依賴的一個重要函數就是 buildFragment,為 DOM 插入提高了性能。
domManip 內對 script 節點元素做了特殊處理
- script 無 type 屬性,預設會執行其內的 JS 腳本
- script 的 type="text/javascript" 或 type="text/ecmascript" ,會執行其內的 JS 腳本
- script 如果有 src 屬性,會執行 $._evalUrl 請求遠程的 JS 文件並執行
- 其它不會執行 JS 腳本,有時我們會用 script 來做 html 模板,如 underscore.js,type="text/template" 或 type="text/plain" 這種,其內的 JS 都不會被執行
此外 dataPriv.access( node, "globalEval" ),這一句標示瞭如果該 script 已經執行過,則不會再次執行。或者說執行後會設置一個 globalEval: true 的標示。
domManip 內部依賴 buildFragment、restoreScript、disableScript、jQuery._evalUrl、DOMEval 這幾個小函數,而 restoreScript、jQuery._evalUrl 也僅在 domManip 用到。
// Replace/restore the type attribute of script elements for safe DOM manipulation function disableScript( elem ) { elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; return elem; } function restoreScript( elem ) { var match = rscriptTypeMasked.exec( elem.type ); if ( match ) { elem.type = match[ 1 ]; } else { elem.removeAttribute( "type" ); } return elem; } jQuery._evalUrl = function( url ) { return jQuery.ajax( { url: url, // Make this explicit, since user can override this through ajaxSetup (#11264) type: "GET", dataType: "script", cache: true, async: false, global: false, "throws": true } ); };
domManip 經歷了各個版本的演變
- 3.0.x 之前版本的 domManip 函數是掛在 jQuery 對象上面的(jQuery.fn.domManip),即通過 $().domManip 方式可以訪問;3.0.x 後 domManip 是一個私有函數,外部無法訪問
- 1.2.x 之前 domManip 有 4 個參數;1.3.x ~ 1.9.x 是 3 個參數;2.x 只有 2 個參數;3.x 有 4 個參數
- 1.9.x 之前的版本 replaceWith 沒有使用 domMainp
相關:
http://www.cnblogs.com/snandy/p/5760742.html