העברת רכיב DOM בלי לאבד את המצב

תכונות אינטרנט: moveBefore()

כשמשנים את ההורה של רכיבי DOM באמצעות שיטות מסורתיות כמו appendChild() או insertBefore(), הדפדפן מסיר את הרכיב מה-DOM באופן משתמע ואז מוסיף אותו למיקום החדש שלו. פעולת "ההסרה וההוספה" הזו מאפסת הרבה מצבים פנימיים, וגורמת לרכיבי <iframe> להיטען מחדש, לאנימציות CSS להתחיל מחדש ולשדות להזנת קלט לאבד את המיקוד.

כדי להעביר רכיב בלי לשנות את המצב שלו, משתמשים ב-API של moveBefore(). השיטה הזו מבצעת העברה אטומית, ועוקפת לחלוטין את שלבי ההסרה וההוספה.

העברת רכיב עם מצב

משתמשים ב-moveBefore() בדיוק כמו שמשתמשים ב-insertBefore(). היא דורשת שני ארגומנטים: הצומת שצריך להעביר, וצומת עזר להוספה לפני (או null להוספה בסוף של ההורה החדש).

const newParent = document.getElementById('new-parent');
const elementWithState = document.getElementById('iframe-or-focused-input');

// MANDATORY: Use moveBefore to preserve state. 
// Passing null as the second argument appends the element to the end of newParent.
newParent.moveBefore(elementWithState, null);

העברת רכיבים בהתאמה אישית (רכיבי אינטרנט)

אם אתם מעבירים רכיבים בהתאמה אישית באמצעות moveBefore(), השיטות של מחזור החיים connectedCallback ו-disconnectedCallback לא יופעלו.

אם הרכיב המותאם אישית צריך לבצע לוגיקה ספציפית כשהוא מועבר, צריך להטמיע את השיטה connectedMoveCallback() בתוך ההגדרה של הרכיב המותאם אישית.

class MyCustomElement extends HTMLElement {
  connectedCallback() {
    // Runs on initial insertion.
  }
  
  connectedMoveCallback() {
    // Runs when the element is moved via moveBefore().
    // Use this to update state that depends on the new DOM location.
  }
}

אסטרטגיות חלופיות

מכיוון ש-moveBefore() הוא שיפור הדרגתי (progressive enhancement), חובה להשתמש בזיהוי תכונות לפני שקוראים לו, ולחזור לפעולות insertBefore() או appendChild() רגילות בדפדפנים ישנים יותר.

const targetParent = document.getElementById('target-container');
const nodeToMove = document.getElementById('moving-element');

// Check if moveBefore is supported on the Element prototype
if ('moveBefore' in Element.prototype) {
  targetParent.moveBefore(nodeToMove, null);
} else {
  // Fallback: traditional move. 
  // Note: This WILL reset <iframe>, animation, and focus state in unsupported browsers.
  targetParent.insertBefore(nodeToMove, null);
}