本节说一下DOM操做模块里的包裹元素子模块,该模块可将当前匹配的元素替换指定的DOM元素,有以下方法:html
举个栗子:node
writer by:大沙漠 QQ:22969969jquery
<!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>
渲染以下:app
对应的DOM树以下:函数
点击按钮1会在全部的P标签上加一个div父节点,以下:源码分析
点击按钮2将在第一个p标签前添加一个div,而后把全部p标签放到div之下,以下:测试
点击按钮3将在第一个p标签前添加一个div>p双层DOM,而后把全部p标签放到div之下,以下:this
点击按钮4将在p标签内最外层嵌套一层div标签,以下:spa
点击按钮5将会去除 span的上一层DOM节点,以下:code
若是再次点击,会将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(); } })