【问题标题】:Can I use JavaScript or CSS to close a previous div?我可以使用 JavaScript 或 CSS 关闭以前的 div 吗?
【发布时间】:2017-09-06 14:32:23
【问题描述】:

我在内容管理系统的限制下工作,有时会迫使我做一些奇怪的事情,因为我无法完全控制 HTML 代码。

在这种情况下,我希望一个 DIV 不嵌套在另一个 DIV 中。由于 CMS 设置,我不能只在 HTML 代码中重新排序 DIV。

所以,我有这个:

<div class="blog">
   <div class="free-me">
      Hello world
   </div>
</div>

我需要的是:

<div class="blog">
</div>
<div class="free-me">
   Hello world
</div>
<div class="blog">
</div>

如果我可以访问 HTML,这就像复制和粘贴一些行一样简单。但是,由于我不能只更改 HTML,所以我想知道是否有任何方法可以使用 CSS 或 JavaScript 来关闭 blog DIV,以便 free-me 可以成为兄弟。

我试过这个(尽管我知道它行不通):

.free-me::before {
    content: '</div>';
}

正如怀疑的那样,那只是将&lt;/div&gt; 的文本渲染到页面中。

对于 JavaScript,我当然不是专家,但您似乎只能使用 document.createElement('div'); 之类的命令插入带有开始和结束标签的完整元素我看不到采用现有 DIV 的明确方法并关闭它。

有没有办法,无论是使用 CSS 还是 JavaScript,我都可以强制 DIV 关闭或插入结尾 &lt;/div&gt; 标记?

注意:最好是非 jQuery 解决方案。

【问题讨论】:

  • 当任何 JS 运行时,浏览器已经做出了让你的标记有效的最佳猜测。我很好奇为什么你需要生成完全无效的html标记(5个打开&lt;div&gt;标签,只有1个关闭)。也许这更像是一个 A-B 问题。
  • 请重新检查您的问题,我猜这不是您想要的输出。
  • alldivs 是否具有相同的类名(在您的示例中为 .blog)? all 孩子divs 是否具有类名(在您的示例中为.free-me)?父母可以包含多个具有该类名的孩子吗?最后,ES6 适合你吗?
  • 如何在编辑器中使用&lt;/div&gt; 开始编写代码,以便在内容之外编写并创建自己的代码,然后使用'
    ` 完成? free-me 是您创建的元素还是由 CMS 生成的,您只能在里面写?
  • @Winter,感谢您的提问。请注意,我不只是让free-me 成为blog 的兄弟姐妹,free-me 拼接blog 以便从本质上讲,博客在free-me 完成后再次启动。不过,如果我有能力让free-me 成为兄弟姐妹,我可能可以从那里开始。

标签: javascript html css


【解决方案1】:

如果你只想在渲染后弹出一个 div,我建议你使用 jQuery insertAfter 方法。我也使用 CMS,并且非常了解您的感受。

$(".free-me").insertAfter(".blog");
.blog {
  border: 1px solid red;
  width: 100px;
  height: 20px;
  text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="blog">
  <div class="free-me">
    Hello world
  </div>
</div>

【讨论】:

  • 如果是这种情况,请使用 id 而不是类。向选择器添加和索引[0] 是一件微不足道的事情。即使有多个具有相同类的元素,我们也可以使用非常具体的选择器通过向其添加父元素来缩小所需元素的范围。
  • 01) 你必须在这附近建立一个厚脸皮,downvotes 是体验的一部分,其中绝大多数不会被解释。 02) 考虑到在评论过程中可能会取消投票者。 03)尝试自己确定答案可能会被否决的原因,这将有助于改善您未来的答案 - 例如,在这种情况下,该问题专门要求非 jQuery 解决方案,正如@SalmanA 指出的那样,这将失败有多个 .blog 元素。 (我是投反对票的,正是出于这两个原因,我投反对票。)
  • @Shaggy 感谢您的关注并感谢您解释原因。在有人向他们指出之前,回答的人可能无法看到他们的错误。
  • @DanPhilip 忽略我之前的评论。我已要求 OP 进行澄清。
【解决方案2】:

您可以使用 JavaScript 实现这一点,方法是遍历类名为 .free-me 的所有元素,并在其父元素的下一个兄弟元素之前将 DOM 插入其中,同时将它们从其父元素中移除。

(function(){
    var children=document.querySelectorAll(".blog>.free-me"),
        x=children.length,
        child,parent;
    while(x--){
        child=children[x];
        parent=child.parentNode;
        // Uncomment below if you would prefer to
        // explicitly remove the child from the parent.
        //parent.removeChild(child);
        parent.parentNode.insertBefore(child,parent.nextSibling);
    }
})();
div{
    margin:5px;
    padding:10px;
}
.blog{
    background:#000;
}
.free-me{
    background:#090;
}
.ignore-me{
    background:#f00;
}
<div class="free-me"></div>
<div class="blog"></div>
<div class="blog">
    <div class="free-me"></div>
</div>
<div class="blog">
    <div class="free-me"></div>
    <div class="free-me"></div>
</div>
<div class="blog">
    <div class="free-me"></div>
    <div class="ignore-me"></div>
    <div class="free-me"></div>
    <div class="free-me"></div>
</div>

但是,如果您的父元素包含多个子元素,其中一些将具有 .free-me 类,而另一些则没有,并且您希望保持所有子元素的顺序,那么解决方案会稍微复杂一些(注意:这个片段有点匆忙,所以可能会清理一下。)

(function(){
    var blogs=document.querySelectorAll(".blog"),
        x=blogs.length,
        grandparent,parent,clone,children,child,y;
    while(x--){
        parent=blogs[x];
        // You can remove the following if statement
        // if you wish to have any pre-existing empty .blog
        // elements removed from the DOM.
        if(parent.querySelector(".free-me")){
            grandparent=parent.parentNode;
            children=parent.children;
            y=children.length;
            while(y--){
                child=children[y];
                if(child.classList.contains("free-me")){
                    if(clone){
                        grandparent.insertBefore(clone,parent.nextSibling)
                        clone=0;
                    }
                    grandparent.insertBefore(child,parent.nextSibling);
                }else{
                    if(!clone)
                        clone=parent.cloneNode(0);
                    clone.insertBefore(child,clone.firstChild);
                }
            }
            grandparent.removeChild(parent);
        }
    }
})();
div{
    margin:5px;
    padding:10px;
}
.blog{
    background:#000;
}
.free-me{
    background:#090;
}
.ignore-me{
    background:#f00;
}
<div class="free-me">1</div>
<div class="blog"></div>
<div class="blog">
    <div class="free-me">2</div>
</div>
<div class="blog">
    <div class="free-me">3</div>
    <div class="free-me">4</div>
</div>
<div class="blog">
    <div class="free-me">5</div>
    <div class="ignore-me">6</div>
    <div class="ignore-me">7</div>
    <div class="free-me">8</div>
</div>
<div class="blog">
    <div class="ignore-me">9</div>
    <div class="free-me">10</div>
    <div class="ignore-me">11</div>
    <div class="free-me">12</div>
</div>
<div class="blog">
    <div class="ignore-me">13</div>
</div>

【讨论】:

  • 如果.blog 没有下一个兄弟姐妹或者它只是在之后插入,会有问题吗?
  • 不,没问题;如果您运行 Snippets,您会看到最后一个父级的子级插入到文档的末尾。
  • 感谢您的回答。我不得不解释说,即使那个答案使用了 jQuery 而你的答案没有,我也给了另一个答案,因为虽然你更符合我的要求,但最后,另一个答案是我可以开始工作的答案.请注意,我确定您的代码是正确的,这可能是我的环境的某些特殊问题导致了问题。
  • 感谢@Questioner 的评论,没问题。如果您想更新您的问题以提供有关您的实施的更多详细信息或评论您在我的解决方案中遇到的问题,我很乐意尝试更新它。可能会导致问题的几件事可能是 IIFE、与 JS 中现有变量名或包含非元素节点(例如文本节点)的 .blog 元素的冲突。
【解决方案3】:

您不能使用 JavaScript 添加结束标记。但是,您可以使用 JavaScript 在 DOM 中移动元素。

假设您想围绕“free-me”div 拆分博客内的内容,这里是 vanilla JavaScript 解决方案(可能不适用于 lame-a** 浏览器):

document.addEventListener("DOMContentLoaded", function() {
  var oldBlog = document.querySelector(".blog");
  var newBlog = document.createElement("div");
  var refNode = oldBlog.querySelector(".free-me");

  // move items after ref node from old blog to new blog
  while (refNode.nextSibling) {
    newBlog.appendChild(refNode.nextSibling);
  }

  // move ref node after old blog
  oldBlog.parentNode.insertBefore(refNode, oldBlog.nextSibling);

  // move new blog after ref node
  refNode.parentNode.insertBefore(newBlog, refNode.nextSibling);

  // set class name
  newBlog.className = "blog";
});
<div class="blog">
  Above
  <div>Above</div>
  <!-- Above -->
  <div class="free-me">Hello world</div>
  Below
  <div>Below</div>
  <!-- Below -->
</div>

这将产生以下 DOM:

<div class="blog">
  Above
  <div>Above</div>
  <!-- Above -->
</div>
<div class="free-me">Hello world</div>
<div class="blog">
  Below
  <div>Below</div>
  <!-- Below -->
</div>

如果您尝试在内容中插入广告,请注意:使用此技巧在 DOM 中移动 iframe 会强制它重新加载;这可能会夸大广告展示次数。

【讨论】:

  • 赞成对文本和 cmets 等非元素节点的良好、简单处理,我的解决方案中没有涉及。但是,就像 Dan 的解决方案一样,这在多个 .blog 和/或 .free-me 元素的情况下不起作用。我还建议克隆旧的 .blog 元素,而不是创建一个新元素,以便保留所有其他属性和类名。
  • 顺便说一下,我为你编辑掉了 jQuery script 标签。
猜你喜欢
相关资源
最近更新 更多
热门标签