Як вставити елемент після іншого елемента в JavaScript без використання бібліотеки?


757

Є insertBefore()в JavaScript, але як я можу вставити елемент за іншим елементом без використання jQuery чи іншої бібліотеки?


4
якщо вам потрібен конкретний випадок останнього дочірнього вузла - stackoverflow.com/questions/5173545 / ...


2
@AlanLarimer, це чудово. Дякую. чи знаєте ви, коли введено insertAdjacentElement?
Xah Lee

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

Відповіді:


1276
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 є останньою дочірньою версією, у якій він повинен додаватиChild.
Бред Фогель

72
Згідно MDN, якщо елемент останній (а значить, наступнийSibling є нульовим), новийNode буде доданий, як очікувалося
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.appendBefore = function (element) {
  element.parentNode.insertBefore(this, element);
},false;

.appendAfter (елемент) Прототип

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

І, щоб побачити все це в дії, запустіть наступний фрагмент коду

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


4
У розширення імен функцій вводять в оману. Він вважає, що його слід називати appendMeBefore і appendMeAfter. Я думав, що він використовується як метод appendChild () , наприклад existingElement.appendAfter(newElement);. Подивіться, що я маю на увазі в цій оновленій jsfiddle .
stomtech

2
Додавати Після роботи, тому що якщо елемент.nextSibling не має наступного брата, nextSibling є NULL, і він додається в кінці.
Стефан Штайгер

45

insertAdjacentHTML + outerHTML

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

Вгору:

  • DRYer: не потрібно зберігати попередній вузол у змінній та використовувати його двічі. Якщо ви перейменовуєте змінну, за меншої кількості змін, щоб змінити.
  • гольфи краще, ніж insertBefore(перерва, навіть якщо назва існуючої змінної вузла три символи)

Недоліки:

  • нижча підтримка веб-переглядача з новіших версій: https://caniuse.com/#feat=insert-adjacent
  • втратить властивості елемента, такі як події, тому що outerHTMLперетворює елемент у рядок. Він потрібен тому, що insertAdjacentHTMLдодає вміст із рядків, а не елементів.

12
Якщо у вас вже створений елемент, ви можете використовувати.insertAdjacentElement()
GetFree

6
Станом на 2018 рік, браузер підтримки виглядає досить тверді: caniuse.com/#feat=insert-adjacent
madannes

Це було приємним рішенням, я пропоную кожному читати цей 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
Іншими словами, це намагання вирішити проблему, яка не існує. Немає нічого суттєво неправильного в додатковій перевірці, але я вважаю, що це не пропагує найкраще розуміння цих методів
1j01

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.

Цей спосіб недоступний у старих веб-переглядачах, тому зазвичай потрібен поліфайл.


Це потребує трохи ручної роботи, щоб реалізувати його як функціонуючу вставку. Однак, на жаль, я не думаю, що це буде працювати правильно.
Містер Сіркоде

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 рік. Однак поліфіл є в документації MDN і використовує безпечніший вид ініціалізації та виконання. Плюс - це для підтримки старих браузерів, у той день і вік, коли прототипи прототипу були не такими поганими.

Як використовувати рішення 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має працювати аналогічно вставці перед . У наведеному нижче коді буде виконано наступне:

  • Якщо дітей немає, 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буде вставлена ​​в кінці дітей, яку потрібно вставити на початку , оскільки в іншому випадку є ' d взагалі не має можливості вставляти в початкове місце цю функцію; з тієї ж причини 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

Запустіть код вище, після чого ви можете вставити новийNode після вказаного referenceNode.
jszhou

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.