本節說一下DOM操作模塊里的包裹元素子模塊,該模塊可將當前匹配的元素替換指定的DOM元素,有如下方法: wrap(html) ;在每個匹配元素的外層添加一層DOM元素 ;該方法會遍歷匹配元素集合,在每個元素上調用.wrapAll()方法 ;不同於wrapAll()的是該方法會在每個匹配元素外面都套一 ...
本節說一下DOM操作模塊里的包裹元素子模塊,該模塊可將當前匹配的元素替換指定的DOM元素,有如下方法:
- wrap(html) ;在每個匹配元素的外層添加一層DOM元素 ;該方法會遍歷匹配元素集合,在每個元素上調用.wrapAll()方法 ;不同於wrapAll()的是該方法會在每個匹配元素外面都套一層html元素。
- wrapAll(html) ;會將html轉化為一個DOM節點並放在第一個匹配元素的前面,再把其他匹配元素也依次放進去 ;html可以是html片段、選擇器表達式、jQuery對象、DOM元素或函數,下同。
- wrapInner(html) ;在每個匹配元素的內容前後包裹HTML元素 ;該方法會遍歷匹配元素集合,並通過調用方法.wrapAll()為每個匹配元素的所有內容包裹一段HTML結構。
- unwrap() ;移除匹配元素集合中每個元素的父標簽,並把匹配元素留在父元素的位置上
舉個慄子:
writer by:大沙漠 QQ:22969969
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script> </head> <body> <p>你好</p> <p>Hello World</p> <div> <i> <span>測試文本</span> </i> </div> <button id="b1">按鈕1</button> <br/> <button id="b2">按鈕2</button><button id="b3">按鈕3</button> <br/> <button id="b4">按鈕4</button><br/><button id="b5">按鈕5</button> <script> b1.onclick=function(){$('p').wrap('<div></div>')} //內部將<div></div>轉化為jQuery對象放到第一個匹配元素<p>你好</p>之前,再將匹配元素移動到該DOM節點內部 b2.onclick=function(){$('p').wrapAll('<div></div>')} //內部將<div></div>轉化為jQuery對象放到第一個匹配元素<p>你好</p>之前,再將匹配元素移動到該DOM節點內部 b3.onclick=function(){$('p').wrapAll('<div><p></p></div>')} //如果含有子節點,則會將匹配元素移動到子節點裡面 b4.onclick=function(){$('p').wrapInner('<div></div>')} //在每個匹配元素的內容前後添加一層DOM節點(包裹層) b5.onclick=function(){$('span').unwrap() } //移除每個匹配元素的父元素,並讓匹配元素占有該節點位置 </script> </body> </html>
渲染如下:
對應的DOM樹如下:
點擊按鈕1會在所有的P標簽上加一個div父節點,如下:
點擊按鈕2將在第一個p標簽前添加一個div,然後把所有p標簽放到div之下,如下:
點擊按鈕3將在第一個p標簽前添加一個div>p雙層DOM,然後把所有p標簽放到div之下,如下:
點擊按鈕4將在p標簽內最外層嵌套一層div標簽,如下:
點擊按鈕5將會去除 span的上一層DOM節點,如下:
如果再次點擊,會將span的上一層DOM繼續移除,直到遇到body節點為止
源碼分析
wrapInner和wrap都是基於wrapAll實現的,wrapAll實現如下:
jQuery.fn.extend({ wrapAll: function( html ) { //在匹配的元素外面放置html元素。html參數可以是html片段、選擇器表達式、jQuery對象、DOM元素或函數。 if ( jQuery.isFunction( html ) ) { //如果html是函數 return this.each(function(i) { jQuery(this).wrapAll( html.call(this, i) ); //遍歷匹配元素,在每個匹配元素上執行html函數,並用該函數的返回值作為參數迭代調用.wrapAll()函數。 }); } if ( this[0] ) { //如果當前有匹配元素 // The elements to wrap the target around var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); //將html轉化為一個jQuery對象 if ( this[0].parentNode ) { //如果當前第一個匹配元素有父元素, wrap.insertBefore( this[0] ); //則把創建的包裹元素插入第一個匹配元素之前。 } wrap.map(function() { //遍歷wrap元素 var elem = this; //elem是創建的包裹元素的引用 while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { //如果html里含有一個子節點 elem = elem.firstChild; //則重置elem為html的子節點,上面的按鈕3會執行到這裡 } return elem; }).append( this ); //這一行的this是當前匹配的jQuery對象,把每個匹配元素移動到插入的元素之後 } return this; }, })
wrapAll首先會把參數轉化為一個jQuery對象,然後插入到當前第一個匹配元素的前面,最後以生成的jQuery對象為主句,調用append()將當前匹配匹配的所有元素添加到新生成的jQuery對象對應的DOM節點內部。對應上面的按鈕2
wrap()實現如下:
jQuery.fn.extend({ wrap: function( html ) { //在每個匹配元素的外層添加一層DOM元素 var isFunction = jQuery.isFunction( html ); //在每個匹配元素前後包裹一段HTML結構,該方法會遍歷匹配元素集合,在每個元素上調用.wrapAll()方法。 return this.each(function(i) { jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); //依次調用wrapALl()函數 }); }, })
wrapInner的實現如下:
jQuery.fn.extend({ wrapInner: function( html ) { //用於在匹配元素集合中每個元素的內容前後包裹一段HTML結構,該方法會遍歷匹配元素集合 if ( jQuery.isFunction( html ) ) { //如果html是函數 return this.each(function(i) { jQuery(this).wrapInner( html.call(this, i) ); //遍歷匹配元素,在每個匹配元素上執行html函數,並用該函數的返回值作為參數迭代調用.wrapInner()函數。 }); } return this.each(function() { //遍歷匹配元素集合 var self = jQuery( this ), contents = self.contents(); //先獲取所有子節點 if ( contents.length ) { //如果有子節點 contents.wrapAll( html ); //調用wrapAll(html)為當前元素的所有內容包裹一段HTML代碼。 } else { self.append( html ); //如果當前元素沒有內容,則直接將參數html插入當前內容。 } }); }, })
unwrap的實現如下:
Query.fn.extend({ unwrap: function() { //移除匹配元素集合中每個元素的父標簽,並把匹配元素留在父元素的位置上 return this.parent().each(function() { //先遍歷父節點 if ( !jQuery.nodeName( this, "body" ) ) { //如果不是body元素 jQuery( this ).replaceWith( this.childNodes ); //則調用replaceWith將this.childNodes替換為this,註意,這裡的this上下文是父節點 } }).end(); } })