jQuery 3.0的domManip淺析

domManip 這個函數的歷史由來已久,從 jQuery 1.0 版本開始便存在了,一直到最新的 jQuery 版本。可謂是元老級工具函數。javascript

 

domManip 的主要功能是爲了實現 DOM 的插入和替換。具體共爲如下 5 個函數服務html

  • 內部後插入(append)
  • 內部前插入(prepend)
  • 外部前插入(before)
  • 外部後插入(after)
  • 替換元素 (replaceWith,1.9.x 以前的版本沒有使用 domMainp)

 

而一個 each 就生成了另外 5 個函數:appendTo、prependTo、insertBefore、insertAfter、replaceAlljava

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 );
	};
} );

 

如圖node

 

內部調用如圖ajax

 

源碼app

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

  1. 先完成 DOM 節點添加
  2. 若是添加的 DOM 節點內有 script 標籤,須要額外處理下。對於可執行的 script (經過type屬性判斷)則執行其內的腳本代碼,其它的則不執行。

 

domManip 依賴的一個重要函數就是 buildFragment,爲 DOM 插入提升了性能。ecmascript

 

domManip 內對 script 節點元素作了特殊處理async

  1. script 無 type 屬性,默認會執行其內的 JS 腳本
  2. script 的 type="text/javascript" 或 type="text/ecmascript" ,會執行其內的 JS 腳本
  3. script 若是有 src 屬性,會執行 $._evalUrl 請求遠程的 JS 文件並執行
  4. 其它不會執行 JS 腳本,有時咱們會用 script 來作 html 模板,如 underscore.js,type="text/template" 或 type="text/plain" 這種,其內的 JS 都不會被執行

此外 dataPriv.access( node, "globalEval" ),這一句標示了若是該 script 已經執行過,則不會再次執行。或者說執行後會設置一個 globalEval: true 的標示。ide


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 經歷了各個版本的演變

  1. 3.0.x 以前版本的 domManip 函數是掛在 jQuery 對象上面的(jQuery.fn.domManip),即經過 $().domManip 方式能夠訪問;3.0.x 後 domManip 是一個私有函數,外部沒法訪問
  2. 1.2.x 以前 domManip 有 4 個參數;1.3.x ~ 1.9.x 是 3 個參數;2.x 只有 2 個參數;3.x 有 4 個參數
  3. 1.9.x 以前的版本 replaceWith 沒有使用 domMainp

 

相關:

http://www.cnblogs.com/snandy/p/5760742.html

相關文章
相關標籤/搜索