Подтвердить что ты не робот

Обтекание набора элементов DOM с использованием JavaScript

У меня есть серия тегов p на моей странице, и я хочу их обернуть в контейнер, например.

<p>foo</p>
<p>bar</p>
<p>baz</p>

Я хочу обернуть все вышеуказанные теги в контейнер следующим образом:

<div>
    <p>foo</p>
    <p>bar</p>
    <p>baz</p>
</div>

Как обернуть NodeList в элемент с использованием ванильного JavaScript?

4b9b3361

Ответ 1

Вы можете сделать следующее:

// create the container div
var dv = document.createElement('div');
// get all divs
var divs = document.getElementsByTagName('div');
// get the body element
var body = document.getElementsByTagName('body')[0];

// apply class to container div
dv.setAttribute('class', 'container');

// find out all those divs having class C
for(var i = 0; i < divs.length; i++)
{
   if (divs[i].getAttribute('class') === 'C')
   {
      // put the divs having class C inside container div
      dv.appendChild(divs[i]);
   }
}

// finally append the container div to body
body.appendChild(dv);

Ответ 2

Ниже представлена ​​чистая версия JavaScript методов jQuery wrap и wrapAll. Я не могу гарантировать, что они работают точно так же, как в jQuery, но они действительно работают очень похожими и должны быть способны выполнять одни и те же задачи. Они работают либо с одним HTMLElement, либо с массивом из них. Я не тестировал, чтобы подтвердить, но они должны работать во всех современных браузерах (и в более ранних версиях).

В отличие от выбранного ответа эти методы поддерживают правильную структуру HTML, используя insertBefore, а также appendChild.

компресс:

// Wrap an HTMLElement around each element in an HTMLElement array.
HTMLElement.prototype.wrap = function(elms) {
    // Convert `elms` to an array, if necessary.
    if (!elms.length) elms = [elms];

    // Loops backwards to prevent having to clone the wrapper on the
    // first element (see `child` below).
    for (var i = elms.length - 1; i >= 0; i--) {
        var child = (i > 0) ? this.cloneNode(true) : this;
        var el    = elms[i];

        // Cache the current parent and sibling.
        var parent  = el.parentNode;
        var sibling = el.nextSibling;

        // Wrap the element (is automatically removed from its current
        // parent).
        child.appendChild(el);

        // If the element had a sibling, insert the wrapper before
        // the sibling to maintain the HTML structure; otherwise, just
        // append it to the parent.
        if (sibling) {
            parent.insertBefore(child, sibling);
        } else {
            parent.appendChild(child);
        }
    }
};

См. рабочую демонстрацию в jsFiddle.

wrapAll:

// Wrap an HTMLElement around another HTMLElement or an array of them.
HTMLElement.prototype.wrapAll = function(elms) {
    var el = elms.length ? elms[0] : elms;

    // Cache the current parent and sibling of the first element.
    var parent  = el.parentNode;
    var sibling = el.nextSibling;

    // Wrap the first element (is automatically removed from its
    // current parent).
    this.appendChild(el);

    // Wrap all other elements (if applicable). Each element is
    // automatically removed from its current parent and from the elms
    // array.
    while (elms.length) {
        this.appendChild(elms[0]);
    }

    // If the first element had a sibling, insert the wrapper before the
    // sibling to maintain the HTML structure; otherwise, just append it
    // to the parent.
    if (sibling) {
        parent.insertBefore(this, sibling);
    } else {
        parent.appendChild(this);
    }
};

См. рабочую демонстрацию на jsFiddle.

Ответ 3

Здесь моя javascript версия wrap(). Короче, но вы должны создать элемент перед вызовом функции.

HTMLElement.prototype.wrap = function(wrapper){
  
  this.parentNode.insertBefore(wrapper, this);
  wrapper.appendChild(this);
}

function wrapDiv(){
  
  var wrapper = document.createElement('div'); // create the wrapper
  wrapper.style.background = "#0cf"; // add style if you want
  
  var element = document.getElementById('elementID'); // get element to wrap
  
  element.wrap(wrapper);
}
div {
  border: 2px solid #f00;
  margin-bottom: 10px;
}
<ul id="elementID">
  <li>Chair</li>
  <li>Sofa</li>
</ul>

<button onclick="wrapDiv()">Wrap the list</button>

Ответ 4

Если вы поддерживаете целевые браузеры, document.querySelectorAll использует селектор CSS:

var targets = document.querySelectorAll('.c'),
  head = document.querySelectorAll('body')[0],
  cont = document.createElement('div');
  cont.className = "container";
for (var x=0, y=targets.length; x<y; x++){
  con.appendChild(targets[x]);
}
head.appendChild(cont);

Ответ 5

Я пришел к этой функции wrapAll, начав с ответа Кевина и установив проблемы, представленные ниже, а также те, которые указаны в комментариях ниже его ответа.

  • Его функция пытается добавить оболочку к следующему брату первого node в переданном узлеList. Это будет проблематично, если этот node также находится в nodeList. Чтобы увидеть это в действии, удалите весь текст и другие элементы между первым и вторым <li> в его демоверсию wrapAll.
  • В отличие от претензии, его функция не будет работать, если несколько узлов передаются в массиве, а не в nodeList из-за используемого метода петли.

Они указаны ниже:

// Wrap wrapper around nodes
// Just pass a collection of nodes, and a wrapper element
function wrapAll(nodes, wrapper) {
    // Cache the current parent and previous sibling of the first node.
    var parent = nodes[0].parentNode;
    var previousSibling = nodes[0].previousSibling;

    // Place each node in wrapper.
    //  - If nodes is an array, we must increment the index we grab from 
    //    after each loop.
    //  - If nodes is a NodeList, each node is automatically removed from 
    //    the NodeList when it is removed from its parent with appendChild.
    for (var i = 0; nodes.length - i; wrapper.firstChild === nodes[0] && i++) {
        wrapper.appendChild(nodes[i]);
    }

    // Place the wrapper just after the cached previousSibling,
    // or if that is null, just before the first child.
    var nextSibling = previousSibling ? previousSibling.nextSibling : parent.firstChild;
    parent.insertBefore(wrapper, nextSibling);

    return wrapper;
}

Смотрите Демо и GitHub Gist.