Envuelva cada 3 div en un div

85

¿Es posible usar nth-childselectores para envolver 3 divs usando .wrapAll? Parece que no puedo resolver la ecuación correcta.

entonces...

<div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
</div>

se convierte en ...

<div>
   <div class="new">
        <div></div>
        <div></div>
        <div></div>
   </div>
   <div class="new">
        <div></div>
        <div></div>
        <div></div>
   </div>
</div>
CSbourne
fuente
2
gist.github.com/3181731 Un buen complemento de jQuery para hacer exactamente eso. Espero que te resulte útil.
iMoses

Respuestas:

179

Puedes hacerlo con .slice(), así:

var divs = $("div > div");
for(var i = 0; i < divs.length; i+=3) {
  divs.slice(i, i+3).wrapAll("<div class='new'></div>");
}

Puede probar una demostración aquí , todo lo que estamos haciendo aquí es obtener los elementos que desea envolver y recorrerlos, hacer un .wrapAll()lote de 3 y luego pasar a los siguientes 3, etc. sin embargo, quedan muchos al final, por ejemplo, 3, 3, 3, 2 si ese es el caso.

Nick Craver
fuente
Haría de esto una función y convertiría el número de divs envueltos en un argumento. Algo como applyDivGrouping (divs, divsPerGroup);
Stefan Kendall
¡Guauu! Gracias por la pronta respuesta. Un par de cosas ... Entonces, solo para aclarar, ¿esto no es posible usando nth-child? & .. Como un novato completo de jQuery, ¿cómo hago para que esto funcione? ¿Lo envuelvo en un jQuery (función ($) ...? Muchas gracias
csbourne
@csbourne - No, :nth-child()no se presta bien a esto, en cuanto a llamar a esto, simplemente envuélvalo en un $(function() { });si desea ejecutarlo document.ready, de lo contrario, llámelo cuando quiera ejecutarlo :)
Nick Craver
Gracias Nick por la fantástica ayuda y orientación, funciona perfectamente.
csbourne
3
@Fahad, según la lógica de NickCraver, simplemente puede editar un pequeño fragmento de código var divs = $("div > .classname");O var divs = $("div .classname");Gracias
23

Escribí una función de fragmento genérico que hace que esto sea bastante fácil de hacer:

$.fn.chunk = function(size) {
    var arr = [];
    for (var i = 0; i < this.length; i += size) {
        arr.push(this.slice(i, i + size));
    }
    return this.pushStack(arr, "chunk", size);
}

$("div > div").chunk(3).wrap('<div class="new"></div>');

Jack
fuente
8

El complemento

$(function() {
    $.fn.EveryWhat = function(arg1) {
        var arr = [];
        if($.isNumeric(arg1)) {
            $.each(this, function(idx, item) {
                var newNum = idx + 1;
                if(newNum%arg1 == 0)
                arr.push(item);
            });
        }
        return this.pushStack(arr, "EveryWhat", "");
    }
});

Cómo usarlo.

Llame EveryWhat()al elemento e ingrese un número para cada elemento que le gustaría recolectar.

$("div").EveryWhat(2).wrapInner('<div class="new" />');

Las citas de wrapinner deben tener un formato adecuado <div class="new" />con una clase y una etiqueta de cierre. Stackoverflow me impide mostrar cómo se ve, pero aquí hay un enlace de un div de cierre automático.

Como debería verse

Eso ajustará todos los demás números que especificó. Estoy usando jquery 1.8.2. así que recuerde usar el selector de llamadas EveryWhat(3)y un número para cada vez. Por supuesto, ponerlo al final de la página o envolverlo en un

$(document).ready(function() {  
    //place above code here
});

Puede usar cada enésimo y luego .wrapInner('<div class="new" />')para obtener los mismos resultados.

Alex Williams
fuente
1
Ya puede hacer esto con $('div > div:nth-child(3n)')y en realidad no resulta en dos grupos de tres elementos.
Ja͢ck
7

Aquí hay una versión más útil de la de Nick anterior:

window.WrapMatch = function(sel, count, className){
  for(var i = 0; i < sel.length; i+=count) {
    sel.slice(i, i+count).wrapAll('<div class="'+className+'" />');
  }
}

Usaría esto como:

var ele = $('#menu > ul > li'); 
window.WrapMatch(ele, 5, 'new-class-name');

La ventana debe ser reemplazada por su espacio de nombres Handlers, por supuesto.

Actualizado: una versión ligeramente mejor que aprovecha jQuery

(function($){
  $.fn.wrapMatch = function(count, className) {
    var length = this.length;
    for(var i = 0; i < length ; i+=count) {
      this.slice(i, i+count).wrapAll('<div '+((typeof className == 'string')?'class="'+className+'"':'')+'/>');
    }
    return this;
  }; 
})(jQuery);

Usar como:

$('.list-parent li').wrapMatch(5,'newclass');

El segundo parámetro para el nombre del contenedor es opcional.

Palmadita
fuente
1
$(function() {
    $.fn.WrapThis = function(arg1, arg2) { /*=Takes 2 arguments, arg1 is how many elements to wrap together, arg2 is the element to wrap*/

        var wrapClass = "column"; //=Set class name for wrapping element

        var itemLength = $(this).find(arg2).length; //=Get the total length of elements
        var remainder = itemLength%arg1; //=Calculate the remainder for the last array
        var lastArray = itemLength - remainder; //=Calculate where the last array should begin

        var arr = [];

        if($.isNumeric(arg1))
        {
            $(this).find(arg2).each(function(idx, item) {
                var newNum = idx + 1;

                if(newNum%arg1 !== 0 && newNum <= lastArray){
                    arr.push(item);
                }
                else if(newNum%arg1 == 0 && newNum <= lastArray) {
                    arr.push(item);
                    var column = $(this).pushStack(arr);
                    column.wrapAll('<div class="' + wrapClass + '"/>'); //=If the array reaches arg1 setting then wrap the array in a column
                    arr = [];
                }
                else if(newNum > lastArray && newNum !== itemLength){ //=If newNum is greater than the lastArray setting then start new array of elements
                    arr.push(item);
                }
                else { //=If newNum is greater than the length of all the elements then wrap the remainder of elements in a column
                    arr.push(item);
                    var column = $(this).pushStack(arr);
                    column.wrapAll('<div class="' + wrapClass + '"/>');
                    arr = []
                }
            });
        }
    }
});

Tomé la idea del complemento de Kyle y la extendí para ajustar automáticamente y tomar dos argumentos. Para empezar, no me funcionó, pero lo hice funcionar con algunas ediciones y adiciones al código.

Para invocar la función, simplemente use el elemento padre de lo que desea ajustar y luego configure sus argumentos de la siguiente manera.

$('#container').WrapThis(5, 'li');

El primer argumento es cuántos elementos desea envolver juntos y el segundo argumento es el tipo de elemento que desea envolver.

Puede cambiar la clase del elemento de envoltura en la función principal bajo la variable wrapClass.

PixelPrecision
fuente
0

He preparado esta respuesta para otra pregunta que era un duplicado de esta. Entonces, tal vez mi variante sea útil para alguien:

Creo que la solución para envolver los tres elementos es:

var $lines = $('.w-col'), // All Dom elelements with class .w-col
     holder = []; //Collect DOM elelements

$lines.each(function (i, item) {
  holder.push(item);

  if (holder.length === 3) {
    $(holder).wrapAll('<div class="w-row" />');
    holder.length  = 0;
  }
});

$(holder).wrapAll('<div class="w-row" />'); //Wrap last elements with div(class=w-row)

Escribí el mismo código en jsbin con algunas mejoras http://jsbin.com/necozu/17/ o http://jsbin.com/necozu/16/

Chekit
fuente