عند إعادة تحديد العناصر الرئيسية لعناصر DOM باستخدام الطرق التقليدية، مثل appendChild() أو insertBefore()، يزيل المتصفّح العنصر ضمنيًا من DOM ثم يدرجه في موقعه الجديد. تؤدي عملية "الإزالة والإدراج" هذه إلى إعادة ضبط العديد من الحالات الداخلية، ما يؤدي إلى إعادة تحميل عناصر <iframe> وإعادة تشغيل صور CSS المتحركة وفقدان التركيز على حقول الإدخال.
لنقل عنصر مع الحفاظ على حالته، استخدِم واجهة برمجة التطبيقات 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() هو تحسين تدريجي، يجب استخدام ميزة "رصد الميزات" قبل استدعائها، والعودة إلى عمليات 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);
}