本节说一下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://www.51sjk.com/Upload/Articles/1/0/267/267587_20210708020315582.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();
}
})
社会混混