jQuery 每个结合 replaceWith 问题

jQuery each combined with replaceWith issue

我试图用 class 遍历每个元素,然后用 div 包裹它,然后继续下一个。

目前正在使用这个...

$('.img-editable').each(function(i) {
    if ($(this).prop("tagName") == "IMG") {
        $(this).replaceWith('<span class="img-edit-container">'+this.outerHTML+'<button class="btn btn-default btn-sm img-edit popover-trigger"><i class="fa fa-file-image-o"></i></button></span>');
    } else {
        $(this).replaceWith('<span class="img-edit-container bg-img-edit-container">'+this.outerHTML+'<button class="btn btn-default bg-img-edit img-edit popover-trigger"><i class="fa fa-file-image-o"></i></button></span>');
    }
});

它适用于简单的情况。但挑战是当有这样的嵌套元素时...

    <div class="img-editable>
        <div id="something else">
            <div class="img-editable"></div>
        </div>
    </div>

然后它分崩离析,内部元素没有正确包装。

我相信 each() 函数正在循环最外层的元素,当它匹配第一个元素时,它会执行 replaceWith() 然后继续。但是当循环到达下一个(内部)时,对匹配的第二个内部元素的引用不再存在(根据浏览器)。

我也试过这个...

var setupImgWrapper = function(elem) {
    if (elem.prop("tagName") == "IMG") {
        elem.replaceWith('<span class="img-edit-container">'+this.outerHTML+'<button class="btn btn-default btn-sm img-edit popover-trigger"><i class="fa fa-file-image-o"></i></button></span>');
        elem.children('.img-edtiable').each(function(i) {
            setupImgWrapper($(this));
        });
    } else {
        elem.replaceWith('<span class="img-edit-container bg-img-edit-container">'+this.outerHTML+'<button class="btn btn-default bg-img-edit img-edit popover-trigger"><i class="fa fa-file-image-o"></i></button></span>');
        elem.children('.img-edtiable').each(function(i) {
            setupImgWrapper($(this));
        });
    }
}

$('.img-editable').each(function(i) {
    setupImgWrapper($(this));
});

这完全失败了。

我很想知道我们如何克服这个问题?在执行 replaceWith() 之后,有没有办法维护 DOM 引用,或者我们可以更新它?

TL;DR 在选定元素上执行 replaceWith 循环后,后代元素引用似乎中断并且这些元素未成功更新。

谢谢!


下面接受的解决方案

$('.img-editable').each(function(i) {
    if ($(this).prop("tagName") == "IMG") {
        $(this).wrap('<span class="img-edit-container"></span>');
        $(this).after('<button class="btn btn-default btn-sm img-edit popover-trigger"><i class="fa fa-file-image-o"></i></button>');
    } else {
        $(this).wrap('<span class="img-edit-container bg-img-edit-container"></span>');
        $(this).after('<button class="btn btn-default bg-img-edit img-edit popover-trigger"><i class="fa fa-file-image-o"></i></button>');
    }
});

jQuery 提供了一个 .wrap() 方法,它可以满足您的需求。

这是一个演示

$('body > div').each(function() {
  $(this).wrap('<div class="wrapper" />');
});
.wrapper {
  border: 1px solid tomato;
  margin-bottom: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div>Normal Element</div>

<div>
  <span>Simple inline element</span>
</div>

<div>
  <div>
    <h1>More Stuff</h1>
  </div>
</div>

如果 .img-editable > ... > .img-editable 破坏了您的代码,您应该更喜欢更适合您需要的选择器。我可以为您提供帮助,只需 post 对此答案发表评论,我们就会解决问题。 :)

试试 wrapall api 和 each

$( ".img-editable" ).wrapAll( "<span class='img-edit-container'/>");

$(".img-edit-container .img-editable").each( function(){
  if ( $( this ).prop("tagName") == "IMG" )
  {
    $(this).parent().append ( '<button class="btn btn-default btn-sm img-edit popover-trigger"><i class="fa fa-file-image-o"></i></button>' );
  }
  else
  {
    $(this).parent().append ( '<button class="btn btn-default bg-img-edit img-edit popover-trigger"><i class="fa fa-file-image-o"></i></button>' );
  }
});

甚至更简单

$( ".img-editable" ).wrapAll( "<span class='img-edit-container'/>");

$(".img-edit-container").append( '<button class="btn btn-default bg-img-edit img-edit popover-trigger"><i class="fa fa-file-image-o"></i></button>' );

$(".img-edit-container img.img-editable").siblings( "button" ).toggleClass( "btn-sm" ).toggleClass( "bg-img-edit" );