将一系列元素包装在另一个元素中的最简洁方法

时间:2017-11-11 10:11:04

标签: javascript html

我有这些HTML:

<div class="main_class">
    <div class="first_part"><img src="0.gif" /></div>
    <span>...</span>
    <img src="1.gif" />
    <img src="2.gif" />
    <img src="3.gif" />
    <div class="end_part"></div>
</div>

span和div之间的图像数量是可变的,我试图用锚标记包装它们以得到这样的结果:

<div class="main_class">
    <div class="first_part"><img src="0.gif" /></div>
    <span>...</span>
    <a href="link">
        <img src="1.gif" />
        <img src="2.gif" />
        <img src="3.gif" />
    </a>
    <div class="end_part"></div>
</div>

我认为这就像获取span并使用outerHTML添加开放式标记一样简单:

mc = document.querySelectorAll(".main_class:not(.modified)");
for (i = 0; i < mc.length; i++) {
    mc[i].classList.add('modified');
    mc[i].children[1].outerHTML += '<a href="link">';
    mc[i].lastElementChild.outerHTML = '</a>' + mc[i].lastElementChild.outerHTML
}

但后来我意识到浏览器太聪明了并自动关闭了标签。是否有一种相对简单的方法可以做到这一点,我不知道?

2 个答案:

答案 0 :(得分:2)

请勿使用outerHTML,但请使用document.createElement.appendChild.insertBefore,...等方法:

&#13;
&#13;
for (let mc of document.querySelectorAll(".main_class:not(.modified)")) {
    mc.classList.add('modified');
    let anchor = document.createElement('a');
    anchor.href = "link";
    for (let child of [...mc.children]) {
        if (child.tagName === 'IMG') {
            mc.insertBefore(anchor, child);
            anchor.appendChild(child);
        }
    }
    console.log(mc.innerHTML);
}
&#13;
<div class="main_class">
    <div class="first_part"><img src="0.gif" /></div>
    <span>...</span>
    <img src="1.gif" />
    <img src="2.gif" />
    <img src="3.gif" />
    <div class="end_part"></div>
</div>
&#13;
&#13;
&#13;

注意:如果你想知道为什么有[...mc.children]而不仅仅是mc.children:这需要获取子元素的副本,否则在循环体中发生的操作会影响mc.children live 集合并使循环错过某些元素。 T.J。的Array.from将绕过同样的事情发生。

答案 1 :(得分:2)

你在考虑标记,但DOM(specsMDN)不是标记,它是一个对象树。从对象的角度思考。创建a元素,然后通过img将现有的appendChild元素移动,然后在div.end_part元素之前插入它。 (除此之外,这意味着附加到它们的任何事件处理程序保持不受干扰,通过标记的往返将会删除。)

由于您只是想在Chrome上运行此功能,因此您可以愉快地利用forEach上的NodeList和箭头功能:

// Find all unhandled .main_class elements
document.querySelectorAll(".main_class:not(.modified)").forEach(mc => {
    // Mark we've done this one
    mc.classList.add("modified");
    // Create our link
    const a = document.createElement("a");
    a.setAttribute("href", "link"); // You can use `a.href = "link"` if it's okay for the attribute to get a resolved value
    // Move the images into it
    Array.from(mc.children).filter(child => child.tagName === "IMG").forEach(img => {
        a.appendChild(img);
    });
    // Insert it before the div.end_part
    mc.insertBefore(a, mc.querySelector("div.end_part"));
});

实例(我在链接周围添加了一个蓝色边框,并在图像周围添加了红色边框,以便我们可以看到它们的位置):

// Find all unhandled .main_class elements
document.querySelectorAll(".main_class:not(.modified)").forEach(mc => {
    // Mark we've done this one
    mc.classList.add("modified");
    // Create our link
    const a = document.createElement("a");
    a.setAttribute("href", "link");
    // Move the images into it
    Array.from(mc.children).filter(child => child.tagName === "IMG").forEach(img => {
        a.appendChild(img);
    });
    // Insert it before the div.end_part
    mc.insertBefore(a, mc.querySelector("div.end_part"));
});
a[href=link] {
  border: 1px solid blue;
}
img {
  border: 1px solid red;
  height: 1em;
  width: 1em;
}
<div class="main_class">
    <div class="first_part"><img src="0.gif" /></div>
    <span>...</span>
    <img src="1.gif" />
    <img src="2.gif" />
    <img src="3.gif" />
    <div class="end_part"></div>
</div>
<div class="main_class">
    <div class="first_part"><img src="0.gif" /></div>
    <span>...</span>
    <img src="1.gif" />
    <img src="2.gif" />
    <img src="3.gif" />
    <div class="end_part"></div>
</div>
<div class="main_class">
    <div class="first_part"><img src="0.gif" /></div>
    <span>...</span>
    <img src="1.gif" />
    <img src="2.gif" />
    <img src="3.gif" />
    <div class="end_part"></div>
</div>