شرح الـ MutationObserver بالتفصيل 🔍
مقدمة سريعة
يا باشمهندسين، النهاردة هنتكلم عن حاجة مهمة جداً في JavaScript وهي الـ MutationObserver. الأداة دي هتساعدك تراقب أي تغيير بيحصل في صفحتك بشكل فوري وفعال.
هو إيه الـ MutationObserver بالظبط؟ 🤔
تخيل إنك عندك كاميرا مراقبة بتصور كل حاجة بتحصل في الـ DOM بتاعك. أي عنصر يتضاف، يتمسح، أو يتعدل، الكاميرا دي هتاخد بالها على طول وتقولك. دي بالظبط وظيفة الـ MutationObserver.
ليه نستخدم MutationObserver؟ 💡
- لما تحتاج تعرف إن فيه حد غير حاجة في الصفحة
- لما تحتاج تعمل حاجة معينة بعد ما يحصل تغيير في الصفحة
- لما تحتاج تتأكد إن التغييرات اللي بتحصل صح
- لما تحتاج تسجل كل التغييرات اللي بتحصل في الصفحة
إزاي نستخدمه؟ (بالخطوات) 🚀
أولاً: إنشاء المراقب (Observer)
const observer = new MutationObserver((mutationsList, observer) => {
mutationsList.forEach((mutation) => {
// هنا هنكتب إيه نعمل لما يحصل تغيير
if (mutation.type === 'childList') {
console.log('فيه عنصر اتضاف أو اتمسح');
} else if (mutation.type === 'attributes') {
console.log('فيه خاصية اتغيرت وهي: ' + mutation.attributeName);
}
});
});
الـ callback function اللي بنمررها للـ MutationObserver بتاخد 2 Arguments
mutationsList: قائمة بكل التغييرات اللي حصلت.
observer: الـ observer نفسه اللي بيتنفذ الكود من خلاله.
تالت حاجة التعامل مع التغييرات بنستخدم forEach loop عشان نمر على كل التغييرات اللي في mutationsList ونتعامل معاها بناءً على نوع التغيير
childList: لو التغيير في الأطفال (إضافة أو حذف عناصر).
attributes: لو التغيير في خصائص العنصر (زي تعديل خاصية معينة).
ثانياً: نحدد إيه اللي عايزين نراقبه
// الإعدادات بتاعت المراقبة
const config = {
attributes: true, // راقب التغييرات في الخصائص
childList: true, // راقب التغييرات في العناصر
subtree: true, // راقب كل العناصر اللي جوه
characterData: true // راقب التغييرات في النصوص
};
// العنصر اللي هنراقبه
const targetNode = document.querySelector('#العنصر-بتاعي');
// نبدأ المراقبة
observer.observe(targetNode, config);
الـarguments بتاعة observe:
- targetNode: العنصر اللي عايزين نراقبه.
- config: إعدادات المراقبة، ودي عبارة عن object بيحدد نوع التغييرات اللي عايزين نتابعها:
- attributes: لو عايزين نتابع التغييرات في خصائص العنصر.
- childList: لو عايزين نتابع التغييرات في الأطفال (إضافة أو حذف عناصر).
- subtree: لو عايزين نتابع التغييرات في كل الnodes اللي تحت العنصر ده.
أمثلة عملية 💪
1️⃣ مراقبة تغييرات الـclasses
// مراقبة تغييرات الكلاسات في عنصر معين
const classObserver = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
console.log('الكلاس اتغير!');
console.log('الكلاسات الجديدة:', mutation.target.className);
}
});
});
classObserver.observe(el, {
attributes: true,
attributeFilter: ['class']
});
2️⃣ مراقبة إضافة عناصر جديدة
// مراقبة إضافة عناصر جديدة في القائمة
const listObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.addedNodes.length > 0) {
console.log('Element added:', mutation.addedNodes[0]);
}
if (mutation.removedNodes.length > 0) {
console.log('Element removed:', mutation.removedNodes[0]);
}
});
});
listObserver.observe(القائمة، {
childList: true
});
3️⃣ مراقبة تغييرات النصوص
// مراقبة تغييرات النصوص في عنصر
const textObserver = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
if (mutation.type === 'characterData') {
console.log('النص اتغير ل:', mutation.target.data);
}
});
});
textObserver.observe(العنصر، {
characterData: true,
subtree: true
});
نصايح مهمة 🎯
- ما تنساش توقف المراقبة: لما تخلص استخدام الـobserver، اعمل:
observer.disconnect();
- استخدم takeRecords: لو عايز تاخد كل التغييرات اللي حصلت لحد دلوقتي:
const changesSnapshot = observer.takeRecords();
- خلي بالك من الأداء: ما تراقبش كل حاجة في الصفحة، ركز بس على العناصر المهمة يعني كمثال في مراقبة التغييرات في الكلاسات:
استخدام attributeFilter: ['class']
ممتاز لأنه بيحدد المراقبة على class attribute بس، وده بيساعد على تحسين الأداء لأنك بتراقب عنصر معين بدل ما تراقب كل الخصائص.
مشاكل شائعة وحلولها 🔧
المشكلة الأولى: المراقب مش شغال
الحل: تأكد إنك:
- عملت observe للعنصر الصح
- حطيت الإعدادات المناسبة
- العنصر موجود في الـ DOM
المشكلة التانية: بيكون سبب في الـmemory leak اللي إتكلمنا عنه قبل كدا
الحل:
- اعمل disconnect لما تخلص
- راقب أقل عدد ممكن من العناصر
- استخدم attributeFilter لو محتاج تراقب خصائص معينة بس
في النهاية 🎉
الـ MutationObserver أداة قوية جداً، بس لازم تستخدمها صح. ما تنساش إن فيه حاجات تانية زي الـ events ممكن تكون أبسط وأسرع في بعض الحالات يعني مبتستخدموش لما تكون التغييرات ممكن تتبعها بأحداث بسيطة زي scroll أو click أو input.