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

评论

如果您需要最后一个子节点的特定情况-stackoverflow.com/questions/5173545 / ...

developer.mozilla.org/en-US/docs/Web/API/Element/…或developer.mozilla.org/en-US/docs/Web/API/Element/…

@AlanLarimer太好了。谢谢。你知道何时引入insertAdjacentElement吗?

根据MDN的说明,IE8和Firefox 48(2016年8月8日)支持该功能。遵循足迹:bugzilla.mozilla.org/show_bug.cgi?id=811259-> w3.org/Bugs/Public/show_bug.cgi?id=19962(2016年3月14日)

#1 楼

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


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

So:

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



您可以使用以下代码段对其进行测试:




 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语法?

– GisjanB
2013年11月14日16:09

如果referenceNode是最后一个子级,则该代码段将无法处理,应该在该子级中添加appendChild。

–布拉德·沃格尔(Brad Vogel)
14-10-8在6:04



根据MDN,如果元素为最后一个元素(因此nextSibling为null),则将按预期方式添加newNode

– electroCutie
2014年11月25日16:07

referenceNode.nextElementSibling是更好的选择

–Bhumi Singhal
16年8月8日在7:30

@BhumiSinghal:错。 insertBefore()可用于文本节点。您为什么要insertAfter()不同?您应该为此分别创建一对名为insertBeforeElement()和insertAfterElement()的函数。

– 7vujy0f0hy
17年3月19日在13:58



#2 楼

简单明了的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> 





在JSFiddle上运行它

评论


扩展功能名称具有误导性。它认为应该将其称为appendMeBefore和appendMeAfter。我认为它的使用类似于appendChild()方法,例如existElement.appendAfter(newElement);。明白我在这个更新的jsfiddle中的意思。

– stomtech
17年5月25日在9:43



Append After工作正常,因为如果element.nextSibling没有下一个同级,则nextSibling为NULL,然后它将在末尾附加。

– Stefan Steiger
19-10-11在14:50

我在jslint中收到警告:预期为';'而是看到','。 },错误;

–caston
11月24日4:23

#3 楼

insertAdjacentHTML + outerHTML

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


优点:


DRYer:您不必将before节点存储在变量中,并且使用两次。如果重命名该变量,则出现的情况要少修改。
insertBefore更好(即使现有节点变量名称的长度为3个字符,也可以中断)



由于新版本而降低了对浏览器的支持:https://caniuse.com/#feat=insert-adjacent

将丢失元素的属性,例如事件,因为outerHTML将元素转换为字符串。我们需要它是因为insertAdjacentHTML从字符串而不是元素中添加内容。


评论


如果已经构造了元素,则可以使用.insertAdjacentElement()

– GetFree
18年3月13日在17:05

截至2018年,浏览器支持看起来非常稳定:caniuse.com/#feat=insert-adjacent

–麦当娜
18年5月30日在14:26

这是一个不错的解决方案,我建议eveyone阅读此xahlee.info/js/js_insert_after.html

–梅雷根(Mehregan Rahmani)
19/12/31在12:45

#4 楼

快速的Google搜索显示了此脚本

// 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的本机解决方案已经解决的问题。他的脚本更快,更高效-我强烈建议您使用该脚本而不是此脚本。

–詹姆斯·朗(James Long)
13年11月11日在11:40

作为JavaScript的通用规则,浏览器执行任务的速度比您编写的任何内容都要快。尽管这两个解决方案在功能上是相同的,但是我的JavaScript解决方案必须先被浏览器理解才能使用,并且每次执行时都需要进行额外的检查。 karim79提供的解决方案将在内部完成所有这些工作,从而节省了这些步骤。这种差异充其量是微不足道的,但他的解决方案是更好的解决方案。

–詹姆斯·朗(James Long)
2014年11月26日17:10

换句话说,它正在尝试解决不存在的问题。额外的检查没有任何内在的错误,但是我想这并没有传播对这些方法的最佳理解

– 1j01
2015年3月23日在2:43

差不多了我将脚本留在这里是因为这是我以前写的那种东西,但是可以接受的答案是更好的答案,可以更好地理解方法,而且速度更快。没有理由改用这个答案-我什至不确定为什么它仍然会被投票

–詹姆斯·朗(James Long)
15年3月23日在11:58

如果targetElement是同级元素中的最后一个元素,则targetElement.nextSibling将返回null。当使用第二个参数null作为第二个参数调用node.insertBefore时,它将在集合的末尾添加该节点。换句话说,if(parent.lastchild == targetElement){分支是多余的,因为parent.insertBefore(newElement,targetElement.nextSibling);即使最初可能会出现其他情况,也可以正确处理所有情况。许多人已经在其他评论中指出了这一点。

–罗夫
16-11-7在11:12



#5 楼

尽管insertBefore()(请参阅MDN)很棒,但在这里大多数答案都引用了它。为了增加灵活性并更加明确,可以使用:

insertAdjacentElement()(请参阅MDN)这使您可以引用任何元素,并将要移动的元素精确插入所需的位置:

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


类似情况下需要考虑的其他问题: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/zh-CN/docs/Web/API/Element/insertAdjacentText

评论


真的应该给这个答案一些爱,这是2020年代即将到来的现代方法。

–赛龙
19-10-28在20:45

这个答案怎么被埋得那么深?我会在某些方面给予奖励,以引起更多关注。

– Qwerty
5月19日20:36

附带一点说明,它不适用于文档片段。

– Lajos Meszaros
8月25日15:08

#6 楼

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

对于两个DOM节点node1node2

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

此方法在较旧的浏览器中不可用,因此通常需要使用polyfill。

评论


但是,这需要一些手动工作才能实现功能正常的insertAfter,因此很遗憾,我认为这不能正常工作。

– SirCode先生
19/12/18在12:42

#7 楼

2018解决方案(不良实践,请到2020年)
我知道这个问题很古老,但是对于任何未来的用户来说,这是一个经过修改的原型
,这只是不存在的.insertAfter函数的微型polyfill
此原型直接向Element原型添加了一个新函数baseElement.insertAfter(element);
 Element.prototype.insertAfter = function(new) {
    this.parentNode.insertBefore(new, this.nextSibling);
}
 

一旦您将polyfill放置在库中,要点或仅在您的代码中(或在任何可以引用它的地方)
只需编写document.getElementById('foo').insertAfter(document.createElement('bar'));

2019解决方案(丑陋,请到2020年)
您不应使用原型。它们会覆盖默认的代码库,并且非常有效或安全,并且可能会导致兼容性错误,但是如果是非商业项目,则没有关系。
如果您想将安全的功能用于商业用途,请使用默认功能。它不是很漂亮,但是可以正常工作:
 function insertAfter(el, newEl) {
    el.parentNode.insertBefore(newEl, this.nextSibling);
}

// use

const el = document.body || document.querySelector("body");
// the || means "this OR that"

el.insertBefore(document.createElement("div"), el.nextSibling);
// Insert Before

insertAfter(el, document.createElement("div"));
// Insert After 
 


2020解决方案
ChildNode的当前Web标准:https ://developer.mozilla.org/zh-CN/docs/Web/API/ChildNode
目前在生活标准中,并且是安全的。
对于不受支持的浏览器,请使用以下Polyfill:https:// github.com/seznam/JAK/blob/master/lib/polyfills/childNode.js
有人说,Polyfill使用Protos,当我说这是不好的做法时。尤其是在盲目使用和覆盖它们的情况下,例如我的2018解决方案。但是,该polyfill在MDN文档中,并且使用一种更安全的初始化和执行。
如何使用2020解决方案:
 // Parent Element
const el = document.querySelector(".class");

// Create New Element
const newEl = document.createElement("div");
newEl.id = "foo";

// Insert New Element BEFORE an Element
el.before(newEl);

// Insert New Element AFTER an Element
el.after(newEl);

// Remove an Element
el.remove();

// Even though it’s a created element,
// newEl is still a reference to the HTML,
// so using .remove() on it should work
// if you have already appended it somewhere
newEl.remove();
 


评论


关于“ 2020解决方案”:在MDN页面上,实验前后将其都标记为“实验性”。期望将来会改变行为。

–izogfif
12月10日13:02

@izogfif好吧,考虑到它刚刚进入生活水平,这是可以预期的。我非常怀疑它们是否会大大改变该方法的行为以适应新的标准。如果他们这样做,我将编辑答案。 MDN文档上存在此问题的唯一原因很可能是因为它是最近添加到生活标准中的,因此即使其稳定且在当前版本中,它仍然是“实验性的”

– SirCode先生
12月10日15:02

#8 楼

或者您可以简单地执行以下操作:

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


评论


我不会想到这种方法。我希望使用@ karim79的直接答案,但请记住。

– Ben J
16-3-24在8:29



#9 楼


步骤1.准备元素:


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



步骤2.附加在:


elementParent.insertBefore(newElement, element.nextSibling);


#10 楼

parentNode.insertBefore()一样使用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>


请注意,扩展DOM可能不是本文所述的适合您的解决方案。

但是,这篇文章写于2010年,现在情况可能有所不同。因此,请自行决定。

JavaScript DOM insertAfter()方法@ jsfiddle.net

#11 楼

这是我们可以使用香草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

评论


并不是的。这会追加到结尾或开头,而不是在另一个元素之后。

–马丁·詹姆斯(Martin James)
8月4日17:12

@MartinJames实际上,它确实附加在另一个元素之后。可能有四种insertPositions:beforebegin-在当前节点之前插入元素beforeend-将元素追加到当前节点的末尾。因此,元素在开始之后成为当前节点的最后一个子节点-将元素添加到当前节点的开头。因此,元素随后成为当前节点的第一个子元素-在当前节点之后插入元素。因此元素成为当前节点的nextSibling

– flash
10月4日1:50

#12 楼

理想情况下,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> 




#13 楼

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

我想要一个具有与parentNode.insertBefore完全相反的行为的函数-也就是说,它必须接受null referenceNode (不会接受已接受的答案)以及insertBefore将在子级末尾插入的位置,这个必须在开头处插入,因为否则,根本无法使用此功能在开头位置插入;与insertBefore插入末尾的原因相同。

由于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
    );
  };
}


#14 楼

实际上,您可以在较新版本的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> 





如预期的那样,它将up元素移动到down元素之后

#15 楼

这段代码可以在最后一个现有子项之后插入链接项,以内联一个小的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);


#16 楼

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

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

评论


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

–梅雷根(Mehregan Rahmani)
19年12月31日在12:03

#17 楼

让我们处理所有情况

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


#18 楼

if( !Element.prototype.insertAfter ) {
    Element.prototype.insertAfter = function(item, reference) {
        if( reference.nextSibling )
            reference.parentNode.insertBefore(item, reference.nextSibling);
        else
            reference.parentNode.appendChild(item);
    };
}


#19 楼

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解决当前问题

–ρяσsρєяK
17年1月15日在4:27

运行上面的代码,然后您可以在指定的referenceNode之后插入一个newNode。

–jszhou
17年1月15日在5:04