Làm cách nào để chèn một phần tử sau phần tử khác trong JavaScript mà không cần sử dụng thư viện?


757

insertBefore()JavaScript, nhưng làm cách nào tôi có thể chèn một phần tử sau phần tử khác mà không cần sử dụng jQuery hoặc thư viện khác?


4
nếu bạn cần trường hợp cụ thể của nút con cuối cùng - stackoverflow.com/questions/5173545/iêu


2
@AlanLarimer thật tuyệt. cảm ơn. Bạn có biết khi nào giới thiệu insertAdjighborEuity không?
Xah Lee

1
Theo MDN, nó được hỗ trợ trong IE8 và Firefox 48 (ngày 08 tháng 8 năm 2016). Theo con đường: bugzilla.mozilla.org/show_orms.cgi?id=811259 -> w3.org/Bugs/Public/show_orms.cgi?id=19962 (ngày 14 tháng 3 năm 2016)
Alan Larimer

Câu trả lời:


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

Đâu referenceNodelà nút bạn muốn đặt newNodesau. Nếu referenceNodelà đứa con cuối cùng trong phần tử cha của nó, điều đó tốt, bởi vì referenceNode.nextSiblingsẽ nullinsertBeforexử lý trường hợp đó bằng cách thêm vào cuối danh sách.

Vì thế:

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

Bạn có thể kiểm tra nó bằng đoạn mã sau:

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
Cảm ơn vì một câu trả lời tuyệt vời, nhưng không khó hiểu khi lật tham chiếuNode và newNode trong danh sách đối số? Tại sao không tuân thủ cú pháp insertB Before?
GijsjanB

9
Đoạn mã này không xử lý nếu tham chiếuNode là con cuối cùng, trong đó nó sẽ appendChild.
Brad Vogel

72
Theo MDN nếu phần tử là cuối cùng (và vì vậy NextSibling là null), newNode sẽ được thêm vào như mong đợi
ElectroCutie

9
ReferenceNode.nextEuitySibling là một lựa chọn tốt hơn để sử dụng
Bhumi Singhal

8
@BhumiSinghal: Sai. insertBefore()làm việc với các nút văn bản. Tại sao bạn muốn insertAfter()khác biệt? Bạn nên tạo một cặp hàm riêng biệt có tên insertBeforeElement()insertAfterElement()cho điều đó.
7vujy0f0hy

116

JavaScript đơn giản sẽ là như sau:

Nối trước:

element.parentNode.insertBefore(newElement, element);

Nối sau:

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

Nhưng, Toss một số nguyên mẫu trong đó để dễ sử dụng

Bằng cách xây dựng các nguyên mẫu sau, bạn sẽ có thể gọi các hàm này trực tiếp từ các phần tử mới được tạo.

  • newElement.appendBefore(element);

  • newElement.appendAfter(element);

.appendB Before (phần tử) Nguyên mẫu

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

.appendAfter (phần tử) Nguyên mẫu

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

Và, để xem tất cả trong hành động, hãy chạy đoạn mã sau

Chạy nó trên JSFiddle


4
Tên hàm mở rộng là sai lệch. Nó nghĩ rằng nó nên được gọi là appendMeB Before và appendMeAfter. Tôi nghĩ rằng nó được sử dụng như Phương thức appendChild () , vd existingElement.appendAfter(newElement);. Xem những gì tôi có ý nghĩa tại jsfiddle cập nhật này .
stomtech

2
Nối sau khi hoạt động, bởi vì nếu phần tử
Stefan Steiger

45

insertAdjacentHTML + outerHTML

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

Ưu điểm:

  • DRYer: bạn không phải lưu trữ nút trước trong một biến và sử dụng nó hai lần. Nếu bạn đổi tên biến, ít xảy ra để sửa đổi.
  • golf tốt hơn insertBefore(hòa vốn ngay cả khi tên biến nút hiện tại dài 3 ký tự)

Nhược điểm:

  • hỗ trợ trình duyệt thấp hơn kể từ mới hơn: https://caniuse.com/#feat=insert-adjighbor
  • sẽ mất các thuộc tính của phần tử như các sự kiện vì outerHTMLchuyển đổi phần tử thành một chuỗi. Chúng tôi cần nó bởi vì insertAdjacentHTMLthêm nội dung từ các chuỗi hơn là các yếu tố.

12
Nếu bạn đã có phần tử được xây dựng, bạn có thể sử dụng.insertAdjacentElement()
GetFree

6
Kể từ năm 2018, hỗ trợ trình duyệt trông khá chắc chắn: caniuse.com/#feat=insert-adjiền
madannes

Đây là một giải pháp tốt, tôi đề nghị eveyone đọc xahlee.info/js/js_insert_after.html
Mehregan Rahmani

37

Một tìm kiếm nhanh của Google cho thấy tập lệnh này

// 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
Đối với bất kỳ ai vấp phải kịch bản này, tôi không khuyên bạn nên sử dụng nó. Nó cố gắng giải quyết các vấn đề mà giải pháp tự nhiên của @ karim79 đã giải quyết. Kịch bản của anh ấy nhanh hơn và hiệu quả hơn - Tôi thực sự khuyên bạn nên sử dụng tập lệnh đó thay vì tập lệnh này.
James Long

10
Là một quy tắc chung trong JavaScript, trình duyệt có thể thực hiện một tác vụ nhanh hơn bất cứ điều gì bạn có thể viết. Mặc dù hai giải pháp này có chức năng giống nhau, nhưng giải pháp JavaScript của tôi cần được trình duyệt đọc hiểu trước khi có thể sử dụng và yêu cầu kiểm tra bổ sung mỗi lần thực thi. Giải pháp được cung cấp bởi karim79 sẽ thực hiện tất cả điều này trong nội bộ, tiết kiệm các bước đó. Sự khác biệt sẽ là tầm thường ở mức tốt nhất, nhưng giải pháp của anh ấy là giải pháp tốt hơn.
James Long

3
Nói cách khác, nó đang cố gắng giải quyết vấn đề không tồn tại. Không có gì sai về kiểm tra thêm, nhưng tôi cho rằng nó không truyền bá sự hiểu biết tốt nhất về các phương pháp này
1j01

3
Khá nhiều. Tôi để lại kịch bản ở đây vì đó là loại mà tôi đã từng viết, nhưng câu trả lời được chấp nhận là câu hỏi hay hơn, cho thấy sự hiểu biết tốt hơn về các phương pháp và nhanh hơn. Không có lý do nào để sử dụng câu trả lời này thay vào đó - tôi thậm chí không chắc tại sao nó vẫn được nâng cấp
James Long

3
Nếu targetEuity là thành phần cuối cùng trong số các anh chị em của nó, thì nó targetElement.nextSiblingsẽ quay trở lại null. Khi node.insertBefoređược gọi với nulltư cách là đối số thứ hai, thì nó sẽ thêm nút ở cuối bộ sưu tập. Nói cách khác, if(parent.lastchild == targetElement) {chi nhánh là không cần thiết, bởi vì parent.insertBefore(newElement, targetElement.nextSibling);sẽ giải quyết đúng đắn với tất cả các trường hợp, mặc dù lúc đầu nó có thể xuất hiện. Nhiều người đã chỉ ra rằng trong các ý kiến ​​khác.
Rolf

26

Mặc dù insertBefore()(xem MDN ) là tuyệt vời và được tham khảo bởi hầu hết các câu trả lời ở đây. Để thêm linh hoạt và để rõ ràng hơn một chút, bạn có thể sử dụng:

insertAdjacentElement()(xem MDN ) Điều này cho phép bạn tham chiếu bất kỳ phần tử nào và chèn phần tử cần di chuyển chính xác vào nơi bạn muốn:

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

Những người khác để xem xét cho các trường hợp sử dụng tương tự: insertAdjacentHTML()insertAdjacentText()

Người giới thiệu:

https://developer.mozilla.org/en-US/docs/Web/API/Euity/insertAdjighborEuity https://developer.mozilla.org/en-US/docs/Web/API/Euity/insertAdjiềnHTML https: // developer.mozilla.org/en-US/docs/Web/API/Euity/insertAdjighborText


Nên thực sự cho câu trả lời này một số tình yêu, đó là cách tiếp cận hiện đại cho những năm 2020 đang nhanh chóng tiếp cận.
huyết thanh

1
Làm thế nào mà câu trả lời này được chôn quá sâu? Tôi sẽ thưởng cho nó một số điểm để mang lại sự chú ý nhiều hơn.
Qwerty

16

Phương thức node.after( doc ) chèn một nút sau một nút khác.

Đối với hai nút DOM node1node2,

node1.after(node2)chèn node2saunode1 .

Phương pháp này không có sẵn trong các trình duyệt cũ hơn, vì vậy thường cần một polyfill.


Điều này cần một chút công việc thủ công để thực hiện như một chức năng chèn. Tuy nhiên, thật không may, tôi không nghĩ rằng nó sẽ hoạt động chính xác.
Ngài SirCode

6

Giải pháp 2018 (Thực hành xấu, đến năm 2020)

Tôi biết câu hỏi này là Ancient, nhưng đối với bất kỳ người dùng nào trong tương lai, đây là một nguyên mẫu được sửa đổi, đây chỉ là một polyfill siêu nhỏ cho hàm .insertAfter không tồn tại nguyên mẫu này trực tiếp thêm một chức năng mới baseElement.insertAfter(element);vào nguyên mẫu Element:

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

Khi bạn đã đặt polyfill trong thư viện, ý chính hoặc chỉ trong mã của bạn (hoặc bất kỳ nơi nào khác có thể được tham chiếu) Chỉ cần viết document.getElementById('foo').insertAfter(document.createElement('bar'));


Giải pháp 2019 (Xấu xí, đến năm 2020)

Chỉnh sửa mới: Bạn KHÔNG NÊN SỬ DỤNG BẢO VỆ. Họ ghi đè lên cơ sở mã mặc định và không hiệu quả hoặc an toàn và có thể gây ra lỗi tương thích, nhưng nếu nó dành cho các dự án phi thương mại thì không thành vấn đề. nếu bạn muốn một chức năng an toàn cho sử dụng thương mại, chỉ cần sử dụng một chức năng mặc định. Nó không đẹp nhưng nó hoạt động:

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 


Giải pháp 2020

Các tiêu chuẩn web hiện tại cho ChildNode: https://developer.mozilla.org/en-US/docs/Web/API/ChildNode

Nó hiện đang ở trong Mức sống và AN TOÀN.

Đối với các trình duyệt không được hỗ trợ, hãy sử dụng Polyfill này: https://github.com/seznam/JAK/blob/master/lib/polyfills/childNode.js

Có người đề cập rằng Polyfill sử dụng Protos, khi tôi nói rằng họ thực hành không tốt. Chúng, đặc biệt là khi chúng được sử dụng không chính xác, như giải pháp của tôi cho năm 2018. Tuy nhiên, polyfill đó có trên Tài liệu MDN và sử dụng một loại khởi tạo và thực thi an toàn hơn. Thêm vào đó, nó hỗ trợ trình duyệt cũ hơn, trong thời đại mà việc ghi đè nguyên mẫu không quá tệ.

Cách sử dụng Giải pháp 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

Hoặc bạn có thể chỉ cần làm:

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

Tôi sẽ không nghĩ về cách tiếp cận đó. Tôi muốn sử dụng câu trả lời trực tiếp hơn của @ karim79 , nhưng nên ghi nhớ.
Ben J

5

Bước 1. Chuẩn bị các yếu tố:

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

Bước 2. Nối sau:

elementParent.insertBefore(newElement, element.nextSibling);

3

Phương thức insertB Before () được sử dụng như thế nào parentNode.insertBefore(). Vì vậy, để bắt chước điều này và thực hiện một phương pháp parentNode.insertAfter()chúng ta có thể viết mã sau đây.

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>

Lưu ý rằng việc mở rộng DOM có thể không phải là giải pháp phù hợp cho Bạn như đã nêu trong bài viết này .

Hovewer, bài viết này được viết vào năm 2010 và bây giờ mọi thứ có thể khác. Vì vậy, quyết định của riêng bạn.

Phương thức chèn JavaScript DOMAfter () @ jsfiddle.net


2

Tốt nhất insertAfternên hoạt động tương tự như insertB Before . Mã dưới đây sẽ thực hiện như sau:

  • Nếu không có con, cái mới Nodeđược nối thêm
  • Nếu không có tài liệu tham khảo Node, cái mới Nodeđược nối thêm
  • Nếu không có Nodesau khi tham chiếu Node, cái mới Nodeđược nối thêm
  • Nếu có tham chiếu Nodecó anh chị em sau, thì cái mới Nodeđược chèn vào trước anh chị em đó
  • Trả lại cái mới Node

Mở rộng Node

Node.prototype.insertAfter = function(node, referenceNode) {

    if (node)
        this.insertBefore(node, referenceNode && referenceNode.nextSibling);

    return node;
};

Một ví dụ phổ biến

node.parentNode.insertAfter(newNode, node);

Xem mã đang chạy


2

Tôi biết câu hỏi này đã có quá nhiều câu trả lời, nhưng không ai trong số chúng đáp ứng yêu cầu chính xác của tôi.

Tôi muốn một hàm có hành vi hoàn toàn ngược lạiparentNode.insertBefore - nghĩa là nó phải chấp nhận một giá trị null referenceNode(mà câu trả lời được chấp nhận không có) và nơi insertBeforenào sẽ chèn vào cuối của những đứa trẻ mà cái này phải chèn vào lúc bắt đầu , vì nếu không thì ' d không có cách nào để chèn tại vị trí bắt đầu với chức năng này cả; cùng lý do insertBeforechèn vào cuối.

Vì null referenceNodeyêu cầu bạn xác định vị trí cha mẹ, chúng ta cần biết cha mẹ - insertBeforelà một phương thức củaparentNode , vì vậy nó có quyền truy cập vào cha mẹ theo cách đó; chức năng của chúng tôi không có, vì vậy chúng tôi sẽ cần truyền cha mẹ làm tham số.

Hàm kết quả trông như thế này:

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

Hoặc (nếu bạn phải, tôi không khuyên bạn) tất nhiên bạn có thể nâng cao Nodenguyên mẫu:

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

0

Mã này hoạt động để chèn một mục liên kết ngay sau khi đứa trẻ hiện tại cuối cùng để nội tuyến một tệp css nhỏ

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

một triển khai mạnh mẽ của 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'."));

};


Thêm một số giải thích với câu trả lời về cách câu trả lời này giúp OP khắc phục vấn đề hiện tại
ρяσѕρєя K

Chạy mã ở trên, sau đó bạn có thể chèn newNode sau tham chiếuNode được chỉ định.
jszhou

0

Hãy xử lý tất cả các tình huống

 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

Bạn thực sự có thể một phương thức gọi là after() trong phiên bản mới hơn của Chrome, Firefox và Opera. Nhược điểm của phương pháp này là Internet Explorer chưa hỗ trợ.

Thí dụ:

// 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)

Mã HTML đơn giản để kiểm tra đó là:

<!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>

Như mong đợi, nó di chuyển phần tử lên sau phần tử xuống

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.