jQuery 3.0的domManip淺析


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 就做了兩件事

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

 

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

 

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

  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 的標示。


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM