Как вставить элемент за другим элементом в JavaScript без использования библиотеки?


758

Есть insertBefore()в JavaScript, но как я могу вставить элемент после другого элемента без использования jQuery или другой библиотеки?


4
если вам нужен конкретный случай самого последнего дочернего узла - stackoverflow.com/questions/5173545/…


2
@AlanLarimer это здорово. Спасибо. Вы знаете, когда введен insertAdjacentElement?
Ха Ли

1
Согласно MDN он поддерживается в IE8 и Firefox 48 (август 2016 года). Следуйте по следу: bugzilla.mozilla.org/show_bug.cgi?id=811259 -> w3.org/Bugs/Public/show_bug.cgi?id=19962 (14 марта 2016 г.)
Алан Лаример

Ответы:


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

Где referenceNodeнаходится узел, который вы хотите разместить newNodeпосле. Если referenceNodeэто последний дочерний элемент в его родительском элементе, это нормально, потому что referenceNode.nextSiblingбудет nullи insertBeforeобрабатывать этот случай, добавляя в конец списка.

Так:

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>


8
Спасибо за отличный ответ, но не смущает ли переворачивание referenceNode и newNode в списке аргументов? Почему бы не соблюдать синтаксис insertBefore?
GijsjanB

9
Этот фрагмент кода не обрабатывается, если referenceNode - последний дочерний элемент, в котором он должен добавить appendChild.
Брэд Фогель

74
Согласно MDN, если элемент является последним (и поэтому nextSibling равен нулю), новый узел будет добавлен, как и ожидалось
electroCutie

9
referenceNode.nextElementSibling - лучший вариант для использования
Bhumi Singhal

8
@BhumiSinghal: Неверно. insertBefore()работает с текстовыми узлами. Почему ты хочешь insertAfter()быть другим? Вы должны создать отдельную пару названных функций insertBeforeElement()и insertAfterElement()для этого.
7vujy0f0hy

116

Простой JavaScript будет следующим:

Добавить до:

element.parentNode.insertBefore(newElement, element);

Добавить после:

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

Но, бросить некоторые прототипы там для удобства использования

Создав следующие прототипы, вы сможете вызывать эти функции непосредственно из вновь созданных элементов.

  • newElement.appendBefore(element);

  • newElement.appendAfter(element);

.appendBefore (element) Prototype

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;

И, чтобы увидеть все в действии, запустите следующий фрагмент кода

Запустите его на JSFiddle


4
В расширение имен функций вводят в заблуждение. Он считает, что он должен называться appendMeBefore и appendMeAfter. Я думал, что он был использован как метод appendChild () , например existingElement.appendAfter(newElement);. Посмотрите, что я имею в виду в этом обновленном jsfiddle .
Стомтех

2
Append After works, потому что если element.nextSibling не имеет следующего родного брата, nextSibling имеет значение NULL, а затем он будет добавлен в конце.
Стефан Штайгер

45

insertAdjacentHTML + outerHTML

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

расквитаться:

  • СУХОЙ: вам не нужно хранить узел before в переменной и использовать его дважды. Если вы переименуете переменную, в меньшей степени, чтобы изменить.
  • гольф лучше, чем insertBefore(безубыточность, если имя переменной существующего узла составляет 3 символа)

Недостатки:

  • более низкая поддержка браузера, так как новее: https://caniuse.com/#feat=insert-adjacent
  • потеряет свойства элемента, такие как события, потому что outerHTMLпреобразует элемент в строку. Нам это нужно, потому что insertAdjacentHTMLдобавляет контент из строк, а не элементов.

12
Если у вас уже есть .insertAdjacentElement()
созданный

6
Начиная с 2018 года поддержка браузеров выглядит довольно солидно: caniuse.com/#feat=insert-adjacent
Маданнес

Это было хорошее решение, я предлагаю каждому прочитать это xahlee.info/js/js_insert_after.html
Мехреган Рахмани

37

Быстрый поиск в 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);
    }
}

29
Для тех, кто сталкивается с этим сценарием, я не рекомендую использовать его. Он пытается решить проблемы, которые уже решает нативное решение @ karim79. Его сценарий быстрее и эффективнее - я настоятельно рекомендую использовать этот сценарий вместо этого.
Джеймс Лонг

10
Как общее правило в JavaScript, браузер может выполнять задачу быстрее, чем все, что вы можете написать. Хотя эти два решения функционально одинаковы, мое решение JavaScript должно быть прочитано понятным браузером, прежде чем его можно будет использовать, и требует дополнительной проверки при каждом выполнении. Решение, предлагаемое karim79, сделает все это внутренне, сохранив эти шаги. Разница в лучшем случае будет тривиальной, но его решение будет лучшим.
Джеймс Лонг

3
Другими словами, он пытается решить проблему, которой не существует. В дополнительной проверке нет ничего неправильного, но я полагаю, что это не
способствует

3
Довольно много. Я оставляю сценарий здесь, потому что это то, что я обычно писал, но принятый ответ лучше, показывает лучшее понимание методов и быстрее. Нет никакой причины использовать этот ответ вместо этого - я даже не уверен, почему он все еще получает голоса
Джеймс Лонг

3
Если targetElement является последним элементом среди своих братьев и сестер, он targetElement.nextSiblingвернется null. Когда node.insertBeforeвызывается со nullвторым аргументом, он добавляет узел в конец коллекции. Другими словами, if(parent.lastchild == targetElement) {ветвление является излишним, потому что parent.insertBefore(newElement, targetElement.nextSibling);будет правильно обрабатывать все случаи, даже если поначалу может показаться иначе. Многие уже отмечали это в других комментариях.
Рольф

26

Хотя 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/en-US/docs/Web/API/Element/insertAdjacentText


Должен действительно дать этому ответу некоторую любовь, это современный подход к 2020-м годам, который быстро приближается.
serraosays

1
Почему этот ответ похоронен так глубоко? Я вознагражу его некоторыми моментами, чтобы привлечь больше внимания.
Qwerty

16

Метод node.after( doc ) вставляет узел после другого узла.

Для двух узлов DOM node1и node2,

node1.after(node2)вставки node2после node1.

Этот метод недоступен в старых браузерах, поэтому обычно требуется полифилл.


Это требует немного ручной работы, чтобы реализовать его как работающую вставку после, так что, к сожалению, я не думаю, что это будет работать правильно.
Мистер SirCode

6

Решение 2018 года (плохая практика, переход к 2020 году)

Я знаю, что этот вопрос является древним, но для любых будущих пользователей, вот модифицированный прототип, это просто микро-заполнение для функции .insertAfter, которой не существует. Этот прототип напрямую добавляет новую функцию baseElement.insertAfter(element);в прототип Element:

Element.prototype.insertAfter = function(new) {
    this.parentNode.insertBefore(new, this.nextSibling);
}

После того, как вы поместили полифил в библиотеку, гист, или просто в свой код (или в любое другое место, где на него можно ссылаться), просто напишите 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: https://developer.mozilla.org/en-US/docs/Web/API/ChildNode

В настоящее время в стандартах жизни и является безопасным.

Для неподдерживаемых браузеров используйте этот Polyfill: https://github.com/seznam/JAK/blob/master/lib/polyfills/childNode.js

Кто-то упомянул, что Polyfill использует Protos, когда я сказал, что это плохая практика. Они, особенно когда они используются неправильно, как мое решение для 2018. Тем не менее, этот polyfill находится в Документации MDN и использует своего рода инициализацию и выполнение, которые более безопасны. Кроме того, это для поддержки старых браузеров, в те времена, когда Prototype Overwriting была не так уж и плоха.

Как использовать решение 2020:

const el = document.querySelector(".class");

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

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

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

// Remove Element
el.remove();

// Remove Child
newEl.remove(); // This one wasnt tested but should work

5

Или вы можете просто сделать:

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

Я бы не подумал об этом подходе. Я бы предпочел использовать более прямой ответ @ karim79 , но хорошо иметь в виду.
Бен Дж

5

Шаг 1. Подготовьте элементы:

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

Шаг 2. Добавить после:

elementParent.insertBefore(newElement, element.nextSibling);

3

Метод 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>

Обратите внимание, что расширение DOM может оказаться не лучшим решением для вас, как указано в этой статье .

Однако эта статья была написана в 2010 году, и сейчас все может быть иначе. Так что решайте сами.

JavaScript DOM метод insertAfter () @ jsfiddle.net


2

В идеале 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);

См код работает


2

Я знаю, что на этот вопрос уже слишком много ответов, но ни один из них не отвечал моим точным требованиям.

Я хотел, чтобы функция имела совершенно противоположное поведениеparentNode.insertBefore - то есть она должна принимать ноль referenceNodeпринятый ответ - нет), и куда insertBeforeбы вставлять в конце дочерние элементы, этот должен вставлять в начале , так как в противном случае не было никакой возможности вставить в начальное местоположение с этой функцией вообще; та же самая причина insertBeforeвставляет в конце.

Поскольку для нуля referenceNodeтребуется, чтобы вы нашли родителя, нам нужно знать, что родитель - insertBeforeэто метод parentNode, поэтому он имеет доступ к родителю таким образом; наша функция этого не делает, поэтому нам нужно передать родителя в качестве параметра.

Результирующая функция выглядит так:

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

0

Этот код работает для вставки элемента ссылки сразу после последнего существующего дочернего элемента для встраивания небольшого файла 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);


0

надежная реализация 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'."));

};


Добавьте некоторое объяснение с ответом о том, как этот ответ помогает ОП в исправлении текущей проблемы
ρяσѕρєя K

Запустите приведенный выше код, затем вы можете вставить новый узел после указанного ссылочного узла.
Янчжоу

0

Давайте разберемся со всеми сценариями

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

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

0

На самом деле вы можете вызвать метод after()в более новых версиях Chrome, Firefox и Opera. Недостатком этого метода является то, что 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>

Как и ожидалось, он перемещает элемент вверх после элемента вниз

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.