【问题标题】:How to insert an element after another element in JavaScript without using a library?如何在不使用库的情况下在 JavaScript 中的另一个元素之后插入一个元素?
【发布时间】:2011-06-15 04:23:08
【问题描述】:

在 JavaScript 中有 insertBefore(),但是如何在不使用 jQuery 或其他库的情况下插入一个元素另一个元素之后?

【问题讨论】:

标签: javascript dom insert append


【解决方案1】:
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);

其中referenceNode 是您要在其后放置newNode 的节点。如果referenceNode 是其父元素中的最后一个子元素,那很好,因为referenceNode.nextSibling 将是nullinsertBefore 通过添加到列表末尾来处理这种情况。

所以:

function insertAfter(newNode, referenceNode) {
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

你可以使用下面的sn-p来测试它:

function insertAfter(referenceNode, newNode) {
  referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

var el = document.createElement("span");
el.innerHTML = "test";
var div = document.getElementById("foo");
insertAfter(div, el);
<div id="foo">Hello</div>

【讨论】:

  • 感谢您的出色回答,但是在参数列表中翻转 referenceNode 和 newNode 会不会令人困惑?为什么不遵守 insertBefore 语法?
  • 如果 referenceNode 是最后一个子节点,则这段代码 sn-p 不处理,它应该 appendChild。
  • 根据MDN,如果元素是最后一个(因此 nextSibling 为空),newNode 将按预期附加
  • referenceNode.nextElementSibling 是一个更好的选择
  • @BhumiSinghal:错了。 insertBefore() 适用于文本节点。为什么你希望insertAfter() 与众不同?您应该为此创建一对单独的函数,分别命名为 insertBeforeElement()insertAfterElement()
【解决方案2】:

快速谷歌搜索显示this script

// create function, it expects 2 values.
function insertAfter(newElement,targetElement) {
    // target is what you want it to go after. Look for this elements parent.
    var parent = targetElement.parentNode;

    // if the parents lastchild is the targetElement...
    if (parent.lastChild == targetElement) {
        // add the newElement after the target element.
        parent.appendChild(newElement);
    } else {
        // else the target has siblings, insert the new element between the target and it's next sibling.
        parent.insertBefore(newElement, targetElement.nextSibling);
    }
}

【讨论】:

  • 对于任何偶然发现这个脚本的人,我不建议使用它。它试图解决@karim79 的本机解决方案已经解决的问题。他的脚本更快、更高效——我强烈建议使用那个脚本而不是这个。
  • 作为 JavaScript 中的一般经验法则,浏览器可以比您编写的任何内容更快地完成任务。尽管这两种解决方案在功能上是相同的,但我的 JavaScript 解决方案需要先被浏览器读取并理解才能使用,并且每次执行时都需要进行额外的检查。 karim79 提供的解决方案将在内部完成所有这些工作,从而节省这些步骤。差异充其量只是微不足道的,但他的解决方案是更好的解决方案。
  • 换句话说,它试图解决一个不存在的问题。额外检查本身并没有错,但我认为它并没有传播对这些方法的最佳理解
  • 差不多。我将脚本留在这里是因为这是我以前写的那种东西,但公认的答案更好,显示对方法的更好理解并且速度更快。没有理由改用这个答案 - 我什至不确定为什么它仍然会得到支持
  • 如果 targetElement 是其兄弟元素中的最后一个元素,则 targetElement.nextSibling 将返回 null。当node.insertBeforenull 作为第二个参数调用时,它将在集合末尾添加节点。换句话说,if(parent.lastchild == targetElement) { 分支是多余的,因为parent.insertBefore(newElement, targetElement.nextSibling); 将正确处理所有情况,即使它一开始可能看起来不是这样。许多人已经在其他 cmets 中指出了这一点。
【解决方案3】:

insertAdjacentHTML + outerHTML

elementBefore.insertAdjacentHTML('afterEnd', elementAfter.outerHTML)

优点:

  • DRYer:您不必将前节点存储在变量中并使用它两次。如果您重命名变量,则修改次数较少。
  • 高尔夫比insertBefore 好(即使现有节点变量名是 3 个字符长也能打破)

缺点:

  • 较新版本的浏览器支持较低:https://caniuse.com/#feat=insert-adjacent
  • 将丢失元素的属性,例如事件,因为outerHTML 将元素转换为字符串。我们需要它,因为 insertAdjacentHTML 从字符串而不是元素添加内容。

【讨论】:

【解决方案4】:

insertBefore() 方法的使用类似于parentNode.insertBefore()。 所以为了模仿这个并制作一个方法parentNode.insertAfter()我们可以编写如下代码。

JavaScript

Node.prototype.insertAfter = function(newNode, referenceNode) {
    return referenceNode.parentNode.insertBefore(
        newNode, referenceNode.nextSibling); // based on karim79's solution
};

// getting required handles
var refElem = document.getElementById("pTwo");
var parent = refElem.parentNode;

// creating <p>paragraph three</p>
var txt = document.createTextNode("paragraph three");
var paragraph = document.createElement("p");
paragraph.appendChild(txt);

// now we can call it the same way as insertBefore()
parent.insertAfter(paragraph, refElem);

HTML

<div id="divOne">
    <p id="pOne">paragraph one</p>
    <p id="pTwo">paragraph two</p>
</div>

请注意,如this article 中所述,扩展 DOM 可能不是适合您的解决方案。

不过,这篇文章写于 2010 年,现在情况可能有所不同。所以你自己决定吧。

JavaScript DOM insertAfter() method @ jsfiddle.net

【讨论】:

    【解决方案5】:

    此代码用于在最后一个现有子项之后插入一个链接项到 inlining 一个小 css 文件

    var raf, cb=function(){
        //create newnode
        var link=document.createElement('link');
        link.rel='stylesheet';link.type='text/css';link.href='css/style.css';
    
        //insert after the lastnode
        var nodes=document.getElementsByTagName('link'); //existing nodes
        var lastnode=document.getElementsByTagName('link')[nodes.length-1]; 
        lastnode.parentNode.insertBefore(link, lastnode.nextSibling);
    };
    
    //check before insert
    try {
        raf=requestAnimationFrame||
            mozRequestAnimationFrame||
            webkitRequestAnimationFrame||
            msRequestAnimationFrame;
    }
    catch(err){
        raf=false;
    }
    
    if (raf)raf(cb); else window.addEventListener('load',cb);
    

    【讨论】:

      【解决方案6】:

      或者你可以简单地这样做:

      referenceNode.parentNode.insertBefore( newNode, referenceNode )
      referenceNode.parentNode.insertBefore( referenceNode, newNode )
      

      【讨论】:

      • 我不会想到这种方法。我更喜欢使用@karim79 的more direct answer,但请记住这一点。
      • 我不推荐这个,但 +1 创意。
      【解决方案7】:

      简单的 JavaScript 如下:

      附加在之前:

      element.parentNode.insertBefore(newElement, element);
      

      后追加:

      element.parentNode.insertBefore(newElement, element.nextSibling);
      

      但是,为了方便使用,请在其中添加一些原型

      通过构建以下原型,您将能够直接从新创建的元素中调用这些函数。

      • newElement.appendBefore(element);

      • newElement.appendAfter(element);

      .appendBefore(element) 原型

      Element.prototype.appendBefore = function (element) {
        element.parentNode.insertBefore(this, element);
      },false;
      

      .appendAfter(element) 原型

      Element.prototype.appendAfter = function (element) {
        element.parentNode.insertBefore(this, element.nextSibling);
      },false;
      

      并且,要查看所有操作,请运行以下代码片段

      /* Adds Element BEFORE NeighborElement */
      Element.prototype.appendBefore = function(element) {
        element.parentNode.insertBefore(this, element);
      }, false;
      
      /* Adds Element AFTER NeighborElement */
      Element.prototype.appendAfter = function(element) {
        element.parentNode.insertBefore(this, element.nextSibling);
      }, false;
      
      
      /* Typical Creation and Setup A New Orphaned Element Object */
      var NewElement = document.createElement('div');
      NewElement.innerHTML = 'New Element';
      NewElement.id = 'NewElement';
      
      
      /* Add NewElement BEFORE -OR- AFTER Using the Aforementioned Prototypes */
      NewElement.appendAfter(document.getElementById('Neighbor2'));
      div {
        text-align: center;
      }
      #Neighborhood {
        color: brown;
      }
      #NewElement {
        color: green;
      }
      <div id="Neighborhood">
        <div id="Neighbor1">Neighbor 1</div>
        <div id="Neighbor2">Neighbor 2</div>
        <div id="Neighbor3">Neighbor 3</div>
      </div>

      Run it on JSFiddle

      【讨论】:

      • extension 函数名称具有误导性。它认为它应该被称为 appendMeBefore 和 appendMeAfter。我认为它像appendChild() Method 一样使用,例如existingElement.appendAfter(newElement);。看看我在这个更新的jsfiddle 的意思。
      • Append 工作后,因为如果 element.nextSibling 没有下一个兄弟,nextSibling 为 NULL,然后会追加到最后。
      • 我在 jslint 中收到警告:预期为 ';'而是看到','。 },假的;
      【解决方案8】:

      方法node.after (doc) 在另一个节点之后插入一个节点。

      对于两个 DOM 节点 node1node2

      node1.after(node2)node1 之后插入node2

      这个方法在旧版浏览器中不可用,所以通常需要一个 polyfill。

      【讨论】:

      • 虽然这需要一些手动工作才能实现为功能 insertAfter,所以不幸的是我认为这不能正常工作。
      【解决方案9】:

      第 1 步。准备元素:

      var element = document.getElementById('ElementToAppendAfter');
      var newElement = document.createElement('div');
      var elementParent = element.parentNode;
      

      第 2 步。添加到 :

      elementParent.insertBefore(newElement, element.nextSibling);
      

      【讨论】:

        【解决方案10】:

        您可以使用appendChild 函数在元素之后插入。

        参考:http://www.w3schools.com/jsref/met_node_appendchild.asp

        【讨论】:

        • 此解决方案不适用于 2 p 标签。您不能使用此功能在另一个 p 标签之后添加一个 p 标签 ..
        【解决方案11】:

        理想情况下,insertAfter 的工作方式应类似于 insertBefore。下面的代码将执行以下操作:

        • 如果没有孩子,则附加新的Node
        • 如果没有引用Node,则附加新的Node
        • 如果引用Node后没有Node,则追加新的Node
        • 如果引用 Node 后面有兄弟,则在该兄弟之前插入新的 Node
        • 返回新的Node

        扩展Node

        Node.prototype.insertAfter = function(node, referenceNode) {
        
            if (node)
                this.insertBefore(node, referenceNode && referenceNode.nextSibling);
        
            return node;
        };
        

        一个常见的例子

        node.parentNode.insertAfter(newNode, node);
        

        查看正在运行的代码

        // First extend
        Node.prototype.insertAfter = function(node, referenceNode) {
            
            if (node)
                this.insertBefore(node, referenceNode && referenceNode.nextSibling);
        
            return node;
        };
        
        var referenceNode,
            newNode;
        
        newNode = document.createElement('li')
        newNode.innerText = 'First new item';
        newNode.style.color = '#FF0000';
        
        document.getElementById('no-children').insertAfter(newNode);
        
        newNode = document.createElement('li');
        newNode.innerText = 'Second new item';
        newNode.style.color = '#FF0000';
        
        document.getElementById('no-reference-node').insertAfter(newNode);
        
        referenceNode = document.getElementById('no-sibling-after');
        newNode = document.createElement('li');
        newNode.innerText = 'Third new item';
        newNode.style.color = '#FF0000';
        
        referenceNode.parentNode.insertAfter(newNode, referenceNode);
        
        referenceNode = document.getElementById('sibling-after');
        newNode = document.createElement('li');
        newNode.innerText = 'Fourth new item';
        newNode.style.color = '#FF0000';
        
        referenceNode.parentNode.insertAfter(newNode, referenceNode);
        <h5>No children</h5>
        <ul id="no-children"></ul>
        
        <h5>No reference node</h5>
        <ul id="no-reference-node">
          <li>First item</li>
        </ul>
        
        <h5>No sibling after</h5>
        <ul>
          <li id="no-sibling-after">First item</li>
        </ul>
        
        <h5>Sibling after</h5>
        <ul>
          <li id="sibling-after">First item</li>
          <li>Third item</li>
        </ul>

        【讨论】:

          【解决方案12】:

          insertAfter 的强大实现。

          // source: https://github.com/jserz/domPlus/blob/master/src/insertAfter()/insertAfter.js
          Node.prototype.insertAfter = Node.prototype.insertAfter || function (newNode, referenceNode) {
            function isNode(node) {
              return node instanceof Node;
            }
          
            if(arguments.length < 2){
              throw(new TypeError("Failed to execute 'insertAfter' on 'Node': 2 arguments required, but only "+ arguments.length +" present."));
            }
          
            if(isNode(newNode)){
              if(referenceNode === null || referenceNode === undefined){
                return this.insertBefore(newNode, referenceNode);
              }
          
              if(isNode(referenceNode)){
                return this.insertBefore(newNode, referenceNode.nextSibling);
              }
          
              throw(new TypeError("Failed to execute 'insertAfter' on 'Node': parameter 2 is not of type 'Node'."));
            }
          
            throw(new TypeError("Failed to execute 'insertAfter' on 'Node': parameter 1 is not of type 'Node'."));
          };
          

          【讨论】:

          • 添加一些解释,说明此答案如何帮助 OP 解决当前问题
          • 运行上面的代码,就可以在指定的referenceNode后面插入一个newNode了。
          【解决方案13】:

          让我们处理所有场景

           function insertAfter(newNode, referenceNode) {
                  if(referenceNode && referenceNode.nextSibling && referenceNode.nextSibling.nodeName == '#text')
                      referenceNode = referenceNode.nextSibling;
          
                  if(!referenceNode)
                      document.body.appendChild(newNode);
                  else if(!referenceNode.nextSibling)
                      document.body.appendChild(newNode);
                  else            
                      referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);            
              }
          

          【讨论】:

            【解决方案14】:

            虽然insertBefore() 很棒并且被这里的大多数答案引用。为了增加灵活性并更明确一点,您可以使用:

            insertAdjacentElement() as refElem.insertAdjacentElement(position, newElem) 允许您引用任何元素,并将要移动的元素准确插入到您想要的位置(位置可以是以下之一:'beforebegin''afterbegin''beforeend'、@987654330 @) 如下图:

            // refElem.insertAdjacentElement('beforebegin', myElem); 
            <p id="refElem">
                // refElem.insertAdjacentElement('afterbegin', myElem);
                ... content ...
                // refElem.insertAdjacentElement('beforeend', myElem);
            </p>
            // refElem.insertAdjacentElement('afterend', myElem); 
            

            类似用例的其他考虑:insertAdjacentHTML()insertAdjacentText()

            参考资料:

            https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentElement https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentText

            【讨论】:

            • 应该真的给这个答案一些爱,它是 2020 年代的现代方法正在迅速接近。
            • 这个答案怎么埋得这么深?我将奖励它一些积分以引起更多关注。
            • 附注一点,它不适用于文档片段。
            【解决方案15】:
            if( !Element.prototype.insertAfter ) {
                Element.prototype.insertAfter = function(item, reference) {
                    if( reference.nextSibling )
                        reference.parentNode.insertBefore(item, reference.nextSibling);
                    else
                        reference.parentNode.appendChild(item);
                };
            }
            

            【讨论】:

              【解决方案16】:

              我知道这个问题已经有太多答案了,但没有一个符合我的确切要求。

              我想要一个与 parentNode.insertBefore 行为完全相反的函数 - 也就是说,它必须接受空值 referenceNodeaccepted answer 不接受),而 insertBefore将在子节点的 end 处插入,这个必须在 start 处插入,否则根本无法使用此函数在起始位置插入;同样的原因 insertBefore 在末尾插入。

              由于 null referenceNode 需要你定位父级,我们需要知道父级 - insertBeforeparentNode 的一个方法,所以它可以通过这种方式访问​​父级;我们的函数没有,所以我们需要将父级作为参数传递。

              生成的函数如下所示:

              function insertAfter(parentNode, newNode, referenceNode) {
                parentNode.insertBefore(
                  newNode,
                  referenceNode ? referenceNode.nextSibling : parentNode.firstChild
                );
              }
              

              或者(如果必须,我不推荐)你当然可以增强Node原型:

              if (! Node.prototype.insertAfter) {
                Node.prototype.insertAfter = function(newNode, referenceNode) {
                  this.insertBefore(
                    newNode,
                    referenceNode ? referenceNode.nextSibling : this.firstChild
                  );
                };
              }
              

              【讨论】:

                【解决方案17】:

                2018 年解决方案(不良做法,转至 2020 年)

                我知道这个问题很古老,但对于任何未来的用户,这里有一个修改过的原型。这只是不存在的 .insertAfter 函数的 polyfill。这个原型直接将函数HTMLElement.insertAfter(element);添加到HTMLElement Prototype中:

                // Parent
                const el = document.body;
                // New Element
                const newEl = document.createElement("div");
                
                // Custom Method
                Element.prototype.insertAfter = function(new) {
                    this.parentNode.insertBefore(new, this.nextSibling);
                }
                
                // Insert Before Element
                el.insertBefore(newEl)
                
                // Insert After Element
                el.insertAfter(newEl);
                
                // Just remember you cant use .insertAfter() or .insertBefore() 
                // after either is already called.
                // You cant place one element in two places at once.
                

                2019 解决方案(丑陋/过时,转到 2020)

                不要使用原型(如 2018 解决方案)。覆盖原型既危险又低质量。如果您需要新方法,请改用函数覆盖。
                如果您想要商业项目的安全功能,只需使用默认功能。它不那么漂亮,但它有效:

                // Parent
                const el = document.body;
                // New Element
                const newEl = document.createElement("div");
                
                // Function You Need
                function insertAfter(el0, el1) {
                    el0.parentNode.insertBefore(el1, el0.nextSibling);
                }
                
                // Insert Before Element
                el.insertBefore(newEl);
                
                // Insert After Element
                insertAfter(el, newEl);
                
                // Just remember you cant use insertAfter() or .insertBefore()
                // after either is already called.
                // You cant place one element in two places at once.
                

                2020 解决方案 - ChildNode

                ChildNode 的当前 Web 标准:MDN Docs - ChildNode

                它目前符合生活标准,可以安全使用。

                对于不支持的浏览器(例如 IE),使用这个 Polyfill:https://github.com/seznam/JAK/blob/master/lib/polyfills/childNode.js

                当我说它们是不好的做法时,我意识到 polyfill 使用了 Proto Overrides。它们是,特别是当它们被盲目使用时,就像我的第一个解决方案一样。但是,MDN 文档中的 polyfill 使用了一种初始化和执行形式,与仅覆盖原型相比,它更加可靠和安全。

                如何使用子节点:

                // Parent 
                const el = document.body;
                // New Element
                const newEl = document.createElement("div");
                
                // Insert Before Element
                el.before(newEl);
                
                // Insert After Element
                el.after(newEl);
                
                // Just remember you cant use .after() or .before()
                // after either is already called.
                // You cant place one element in two places at once.
                
                // Another feature of ChildNode is the .remove() method,
                // which deletes the element from the DOM
                el.remove();
                newEl.remove();
                

                【讨论】:

                • 关于“2020 解决方案”:beforeafter 在 MDN 页面上都标记为“实验性”:Experimental. Expect behavior to change in the future.
                • @izogfif 好吧,考虑到它刚刚进入生活水平,这是意料之中的。我非常怀疑他们会显着改变该方法的行为以适应新标准。如果他们这样做,我将编辑答案。 MDN 文档中的唯一原因很可能是因为它最近被添加到了生活标准中,所以它仍然是“实验性的”,即使它稳定并且在当前版本中
                • 它运行良好。完全支持除 IE。
                • @Mircea 如果您希望它在 IE 上运行,请使用我的回答中建议的 polyfill。 (虽然老实说,我怀疑有人真的关心 IE 了,我个人不再支持它了)
                【解决方案18】:

                您实际上可以在较新版本的 Chrome、Firefox 和 Opera 中使用名为 after() 的方法。这种方法的缺点是 Internet Explorer 还不支持它。

                例子:

                // You could create a simple node
                var node = document.createElement('p')
                
                // And then get the node where you want to append the created node after
                var existingNode = document.getElementById('id_of_the_element')
                
                // Finally you can append the created node to the exisitingNode
                existingNode.after(node)
                

                要测试的简单 HTML 代码是:

                <!DOCTYPE html>
                <html>
                <body>
                     <p id='up'>Up</p>
                    <p id="down">Down</p>
                  <button id="switchBtn" onclick="switch_place()">Switch place</button>
                  <script>
                    function switch_place(){
                      var downElement = document.getElementById("down")
                      var upElement = document.getElementById("up")
                      downElement.after(upElement);
                      document.getElementById('switchBtn').innerHTML = "Switched!"
                    }
                  </script>
                </body>
                </html>

                正如预期的那样,它将向上元素移动到向下元素之后

                【讨论】:

                  【解决方案19】:

                  这是我们可以使用 vanilla javascript 在一个元素之后添加一个元素的最简单方法

                  var d1 = document.getElementById('one');
                  d1.insertAdjacentHTML('afterend', '<div id="two">two</div>');
                  

                  参考: https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML

                  【讨论】:

                  • 并非如此。这附加到结尾或开头,而不是在另一个元素之后。
                  • @MartinJames 它实际上确实附加在另一个元素之后。有四种可能的 insertPosition: beforebegin - 在当前节点之前插入元素 beforeend - 将元素追加到当前节点的末尾。所以元素在开始之后成为当前节点的最后一个子节点 - 将元素添加到当前节点的开头。所以元素成为当前节点后的第一个子节点 - 在当前节点之后插入元素。所以元素成为当前节点的nextSibling
                  猜你喜欢
                  • 2011-11-20
                  • 2011-08-22
                  • 2011-01-15
                  • 1970-01-01
                  • 2016-02-08
                  • 1970-01-01
                  • 2015-11-21
                  • 1970-01-01
                  相关资源
                  最近更新 更多