使用 JavaScript 包装一组 DOM 元素

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3337587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:14:20  来源:igfitidea点击:

Wrapping a set of DOM elements using JavaScript

javascript

提问by

I have a series of ptags on my page and I want to wrap them all into a container, e.g.

我的p页面上有一系列标签,我想将它们全部包装到一个容器中,例如

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

I want to wrap all the above tags into a container as follows:

我想将上述所有标签包装到一个容器中,如下所示:

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

How to wrap a NodeListin an element using vanilla JavaScript?

如何NodeList使用 vanilla JavaScript将 a 包装在元素中?

采纳答案by Sarfraz

You can do like this:

你可以这样做:

// 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);

回答by Kevin Jurkowski

Posted below are a pure JavaScript version of jQuery's wrapand wrapAllmethods. I can't guarantee they work exactlyas they do in jQuery, but they do in fact work very similarly and should be able to accomplish the same tasks. They work with either a single HTMLElement or an array of them. I haven't tested to confirm, but they should both work in all modern browsers (and older ones to a certain extent).

下面发布的是 jQuerywrapwrapAll方法的纯 JavaScript 版本。我不能保证它们的工作方式与在 jQuery 中完全一样,但实际上它们的工作方式非常相似,并且应该能够完成相同的任务。它们使用单​​个 HTMLElement 或它们的数组。我还没有测试确认,但它们应该都可以在所有现代浏览器中工作(在一定程度上也是旧浏览器)。

Unlike the selected answer, these methods maintain the correct HTML structure by using insertBefore as well as appendChild.

与选择的答案不同,这些方法通过使用 insertBefore 和 appendChild 来维护正确的 HTML 结构。

wrap:

裹:

// 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);
        }
    }
};

See a working demoon jsFiddle.

请参阅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);
    }
};

See a working demoon jsFiddle.

请参阅jsFiddle 上的工作演示

回答by Web_Designer

I arrived at this wrapAllfunction by starting with Kevin's answerand fixing the problems presented below as well as those mentioned in the comments below his answer.

wrapAll通过从凯文的回答开始并解决下面提出的问题以及他的回答下面的评论中提到的问题来实现这个功能。

  1. His function attempts to append the wrapper to the next sibling of the first node in the passed nodeList. That will be problematic if that node is also in the nodeList. To see this in action, remove all the text and other elements from between the first and second <li>in his wrapAll demo.
  2. Contrary to the claim, his function won't work if multiple nodes are passed in an array rather than a nodeList because of the looping technique used.
  1. 他的函数尝试将包装器附加到传递的 nodeList 中第一个节点的下一个兄弟节点。如果该节点也在 nodeList 中,那将是有问题的。要看到这个动作,删除所有文本,并从第一和第二之间的其他元素<li>他的wrapAll演示
  2. 与声明相反,由于使用了循环技术,如果在数组而不是 nodeList 中传递多个节点,则他的函数将不起作用。

These are fixed below:

这些是固定的:

// 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;
}

See the Demoand GitHub Gist.

请参阅演示GitHub 要点

回答by pmrotule

Here's my javascript version of wrap(). Shorter but you have to create the element before calling the function.

这是我的 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>

回答by Rixius

If you're target browsers support it, the document.querySelectorAlluses CSS selectors:

如果您的目标浏览器支持它,则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);

回答by Oneezy

Taking @Rixius 's answer a step further, you could turn it into a forEach loop with an arrow function

将@Rixius 的回答更进一步,您可以将其转换为带有箭头函数的 forEach 循环

let parent = document.querySelector('div');
let children = parent.querySelectorAll('*');
let wrapper = document.createElement('section');

wrapper.className = "wrapper";

children.forEach((child) => {
    wrapper.appendChild(child);
});

parent.appendChild(wrapper);
* { margin: 0; padding: 0; box-sizing: border-box; font-family: roboto; }
body { padding: 5vw; }
span,i,b { display: block; }

div { border: 1px solid lime; margin: 1rem; }
section { border: 1px solid red; margin: 1rem; }
<div>
 <span>span</span>
 <i>italic</i>
 <b>bold</b>
</div>