Ищите функцию jQuery, похожую на wrapAll, которая будет переносить только последовательные элементы - PullRequest
5 голосов
/ 18 ноября 2011

Существует ли версия wrapAll, которая будет переносить только последовательные элементы? Итак, это:

<p>foo</p>
<p>foo</p>
<h2>bar</h2>
<p>foo</p>

превращается в это:

<div>
    <p>foo</p>
    <p>foo</p>
</div>
<h2>bar</h2>
<div>
    <p>foo</p>
</div>

Когда это запустится?

$('p').wrapAll2('<div />')

Ответы [ 3 ]

6 голосов
/ 18 ноября 2011

Вот один из способов сделать это:

$(function(){
    var cWrap=$('<div />');
    $('p').each(function(){
        var o = $(this).next('p').length;
        $(this).replaceWith(cWrap).appendTo(cWrap);
        if (!o) cWrap=$('<div />');
    });
});

или как полноценный плагин:

(function($){
    $.fn.wrapAll2 = function(wrapper){
        if (!this.length) return this;
        var cWrap=$(wrapper),
            tag = this.get(0).nodeName.toLowerCase();
        return this.each(function(){
            var o = $(this).next(tag).length;
            $(this).replaceWith(cWrap).appendTo(cWrap);
            if (!o) cWrap = $(wrapper);
        });
    };
})(jQuery);
$(function(){
    $('p').wrapAll2('<div />');
});

* Обратите внимание, что предполагается, что вы будете вызывать его в однородных коллекциях (как минимумвсе один и тот же тип узла)

EDIT

Экспериментально я изучил внутренности jQuery и обнаружил, что в нем хранится селектор, использованный для создания коллекции![по крайней мере, при создании экземпляра], поэтому, имея в виду, я создал другую версию, которая по крайней мере работает с текущей версией jQuery, и принимает любой селектор !

(function($) {
    $.fn.wrapAll2 = function(wrapper) {
        if (!this.length) return this;
        var wrap = $(wrapper),
            sel = this.selector || this.get(0).nodeName.toLowerCase();
        return this.each(function() {
            var more = $(this).next(sel).length;
            console.log(this,more);
            $(this).replaceWith(wrap).appendTo(wrap);
            if (!more) wrap = $(wrapper);
        });
    }
})(jQuery);
$(function() {
    $('p, span').wrapAll2('<div />');
});

It не работает с такими вещами, как это: $('p').add('span').wrapAll2('<div />');

2 голосов
/ 18 ноября 2011

Я изложил превосходный ответ Шэда и создал некоторый код, который будет принимать любой селектор, а не только типы узлов:

(function($){
    $.wrapAll2 = function(sel, wrapSel) {
        var wrap = $(wrapSel);
        $(sel).each(function() {
            var more = $(this).next(sel).length;
            $(this).replaceWith(wrap).appendTo(wrap);
            if (!more) wrap = $(wrapSel);
        });
    };
})(jQuery);
$(function() {
    $.wrapAll2('p', '<div/>');
});

Хотелось бы, чтобы ему можно было передать объект JQuery вместо строки селектора, но это работаетдостаточно хорошо для моих целей сейчас.

1 голос
/ 14 августа 2012

Вот общее решение, которое работает для любого селектора jQuery , а также работает, когда коллекция была изменена , например, с использованием add() или andSelf() или not():

Демонстрация: http://jsfiddle.net/wujX6/

(function($){
  $.fn.wrapConsecutive = function(wrapper){
    if (!this.length) return this;
    var thisRun,prev;
    this.each(function(){
      if (!prev || $(this).prev()[0]!=prev){
        if (thisRun) thisRun.wrapAll(wrapper);
        thisRun = $();
      }
      thisRun = thisRun.add(this);
      prev = this;
    });
    if (thisRun) thisRun.wrapAll(wrapper);
    return this;
  };
})(jQuery);

Демонстрация, демонстрирующая его работу на основе управляемых коллекций: http://jsfiddle.net/wujX6/1/


Единственное предостережение в том, что промежуточные текстовые узлы между последовательными элементами не включаются в перенос.Так, например, вызов $('p').wrapConsecutive('<div/>') для этого HTML:

<p>foo</p>
<p>bar</b>
jim
<p>baz</p>
jar

… приведет к следующему выводу:

<div><p>foo</p><p>bar</b><p>baz</p></div>
jim
jar
...