ResizeMonitorer: إنها مثل document.onresize للعناصر

تتيح لك ResizeObserver معرفة عند تغيُّر حجم أحد العناصر.

قبل ResizeObserver، كان عليك إرفاق مستمع إلى resize الخاص بالمستند. الحدث لتلقي إشعار بأي تغيير في أبعاد إطار العرض. في الفعالية سيتعين عليك عندئذٍ معرفة العناصر التي تأثرت التي تتغير ويستدعي روتينًا معينًا للتفاعل بشكل مناسب. إذا كنت بحاجة إلى الأبعاد الجديدة لعنصر ما بعد تغيير الحجم، كان عليك استدعاء getBoundingClientRect() أو getComputedStyle()، ما قد يؤدي إلى إنشاء تنسيق إذا لم تعمد إلى تجميع كل القراءات وكل يكتب.

هذا لم يتناول حتى الحالات التي تغير فيها العناصر حجمها بدون تم تغيير حجم النافذة. على سبيل المثال، إلحاق أطفال جدد وتعيين نمط display للعنصر إلى none، أو يمكن أن تغير إجراءات مشابهة حجم عنصر ما أو أشقائه أو أسلافه.

هذا هو السبب في أن ResizeObserver هو أساس مفيد. تتفاعل مع التغييرات في أي حجم من العناصر المرصودة، بغض النظر عن تسبب التغيير. يوفر الوصول إلى الحجم الجديد للعناصر المرصودة أيضًا.

دعم المتصفح

  • Chrome: 64.
  • الحافة: 79.
  • Firefox: 69.
  • Safari: الإصدار 13.1.

المصدر

واجهة برمجة التطبيقات

تشترك جميع واجهات برمجة التطبيقات التي تتضمّن اللاحقة Observer التي ذكرناها أعلاه في واجهة برمجة تطبيقات بسيطة. التصميم. ResizeObserver ليس استثناءً. تُنشئ عنصر ResizeObserver وتمرير استدعاء إلى الدالة الإنشائية. يتم تمرير دالة الاستدعاء صفيفًا من ResizeObserverEntry عنصرًا (إدخال واحد لكل عنصر تم رصده) على الأبعاد الجديدة للعنصر.

var ro = new ResizeObserver(entries => {
  for (let entry of entries) {
    const cr = entry.contentRect;

    console.log('Element:', entry.target);
    console.log(`Element size: ${cr.width}px x ${cr.height}px`);
    console.log(`Element padding: ${cr.top}px ; ${cr.left}px`);
  }
});

// Observe one or multiple elements
ro.observe(someElement);

بعض التفاصيل

ما الذي يتم الإبلاغ عنه؟

بشكل عام، ResizeObserverEntry تقوم بالإبلاغ عن مربع محتوى أحد العناصر من خلال خاصية تسمى contentRect، التي تُرجع DOMRectReadOnly . مربّع المحتوى هو المربّع الذي يمكن وضع المحتوى فيه. من المهم مربع الحد مطروحًا منه المساحة المتروكة.

رسم تخطيطي لنموذج مربع CSS

تجدر الإشارة إلى أنّه على الرغم من أنّ السمة ResizeObserver تُبلغ عن السمتَين contentRect والمساحة المتروكة، فإنه يشاهد contentRect فقط. لا تخلط بين contentRect ومربّع إحاطة العنصر. الحدود الذي تم الإبلاغ عنه بواسطة getBoundingClientRect() هو المربع الذي يحتوي على العنصر بالكامل وعناصره الفرعية. وتُعد ملفات SVG استثناءً للقاعدة، حيث سيبلغك ResizeObserver عن أبعاد مربّع الإحاطة.

بدءًا من إصدار Chrome 84، أصبح لدى ResizeObserverEntry ثلاث خصائص جديدة لتوفير المزيد للحصول على معلومات تفصيلية. تعرض كل سمة من هذه السمات علامة ResizeObserverSize يحتوي على السمة blockSize والسمة inlineSize. هذا النمط حول العنصر الذي تمت ملاحظته في وقت استدعاء الاتصال.

  • borderBoxSize
  • contentBoxSize
  • devicePixelContentBoxSize

تعرض جميع هذه العناصر صفائف للقراءة فقط لأنه من المأمول في المستقبل يمكنها دعم العناصر التي تحتوي على أجزاء متعددة، والتي تحدث في سيناريوهات متعددة الأعمدة. في الوقت الحالي، ستحتوي هذه الصفائف على عنصر واحد فقط.

توافق النظام الأساسي مع هذه الخصائص محدود، ولكن Firefox موجود تتوافق مع الأولين.

متى يتم الإبلاغ عن ذلك؟

تنص المواصفات على أنّه على "ResizeObserver" معالجة جميع أحداث تغيير الحجم. قبل الطلاء وبعد التخطيط. يصبح هذا استدعاء ResizeObserver مكانًا مثاليًا لإجراء تغييرات على تخطيط صفحتك. لأنّ "ResizeObserver" تتم المعالجة بين التنسيق والرسم، ما يؤدي إلى إلغاء صلاحية والتخطيط، وليس الطلاء.

فهمت

قد تتساءلون عمّا يحدث إذا غيّرتُ حجم لعبة داخل رد الاتصال بـ ResizeObserver؟ الإجابة هي: سوف تقوم مكالمة أخرى فورًا إلى جهة معاودة الاتصال. لحسن الحظ، لدى ResizeObserver لتجنب حلقات معاودة الاتصال اللانهائية والتبعيات الدورية. ستؤدي التغييرات إلى لا تتم معالجته إلا في الإطار نفسه إذا كان العنصر الذي تم تغيير حجمه أعمق في DOM مقارنةً بالعنصر shallowest الذي تمت معالجته في عملية الاستدعاء السابقة. وإلا، سيتم تأجيلها إلى الإطار التالي.

طلب الانضمام

أحد الإجراءات التي تتيح لك السمة ResizeObserver تنفيذها هو تنفيذ كل عنصر. والاستعلامات عن الوسائط. من خلال مراقبة العناصر، يمكنك تحديد نقاط توقف التصميم وتغيير أنماط العنصر. في ما يلي مثال، المربّع الثاني تغيير نصف قطر حده وفقًا لعرضه.

const ro = new ResizeObserver(entries => {
  for (let entry of entries) {
    entry.target.style.borderRadius =
        Math.max(0, 250 - entry.contentRect.width) + 'px';
  }
});
// Only observe the second box
ro.observe(document.querySelector('.box:nth-child(2)'));

هناك مثال آخر مثير للاهتمام وهو نافذة الدردشة. المشكلة التي تنشأ في تخطيط محادثة نموذجي من أعلى إلى أسفل هو موضع التمرير. لتجنُّب إرباك المستخدم، فمن المفيد أن تنتقل النافذة إلى أسفل محادثة، حيث تظهر أحدث الرسائل. بالإضافة إلى ذلك، يمكن لأي نوع من التخطيط تغيير (التفكير في انتقال الهاتف من الوضع الأفقي إلى الوضع العمودي أو العكس) تحقق الشيء نفسه.

يسمح لك ResizeObserver بكتابة رمز واحد يهتم بـ كلا السيناريوهين. إنّ تغيير حجم النافذة هو حدث يمكن لـ ResizeObserver الالتقاط حسب التعريف، ولكن استدعاء appendChild() يؤدي أيضًا إلى تغيير حجم هذا العنصر (ما لم يتم تعيين overflow: hidden)، لأنها تحتاج إلى توفير مساحة للجدول الجديد عناصر. مع وضع ذلك في الاعتبار، يستغرق الأمر عددًا قليلاً جدًا من الأسطر لتحقيق التأثير:

const ro = new ResizeObserver(entries => {
  document.scrollingElement.scrollTop =
    document.scrollingElement.scrollHeight;
});

// Observe the scrollingElement for when the window gets resized
ro.observe(document.scrollingElement);

// Observe the timeline to process new messages
ro.observe(timeline);

أنيق جدًا، أليس كذلك؟

من هنا، يمكنني إضافة المزيد من التعليمات البرمجية للتعامل مع الحالة التي انتقل فيها المستخدم إلى الأسفل. يدويًا ويريد التمرير للالتزام بتلك الرسالة عند ظهور الدور.

هناك حالة استخدام أخرى لأي نوع من العناصر المخصّصة التي تؤدي تنسيقها الخاص. لغاية ResizeObserver، لم تتوفّر طريقة موثوقة لتلقّي إشعار عند انتهاء وأبعادها بحيث يمكن وضع عناصرها الثانوية مرة أخرى.

التأثيرات على مدى استجابة الصفحة لتفاعلات المستخدم (INP)

مدى استجابة الصفحة لتفاعلات المستخدم (INP) هو مقياس يقيس الاستجابة العامة للصفحة لتفاعلات المستخدم. إذا كان مقياس INP للصفحة مضبوطًا على "الجيد" الحد - وهو 200 مللي ثانية أو أقل - يمكن القول إن الصفحة تستجيب بشكل موثوق وتفاعلات المستخدم معها.

وفي حين أن مقدار الوقت الذي يستغرقه تشغيل عمليات استدعاء الحدث استجابةً أن يساهم تفاعل المستخدم بشكل كبير في إجمالي وقت الاستجابة للتفاعل فهذا ليس الجانب الوحيد من مدى استجابة الصفحة لتفاعلات المستخدم (INP). كما يأخذ INP في الاعتبار أيضًا مقدار الوقت الذي يستغرقه سرعة عرض الصفحة التالية من التفاعل. هذه هي مقدار الوقت المستغرق في عملية العرض اللازمة لتعديل بيانات المستخدم واجهة المستخدم استجابة لتفاعل لإكماله.

وعند حدوث مشكلة في السمة ResizeObserver، يُعتبر ذلك مهمًا لأنّ معاودة الاتصال التي يتم تشغيل مثيل ResizerObserver قبل عرض العمل مباشرةً. هذا النمط عن طريق الخطأ، حيث يجب أخذ العمل الذي يحدث في معاودة الاتصال فمن المرجح أن يتطلب هذا العمل تغييرًا في واجهة المستخدم.

عليك الحرص على عرض القليل من الرسومات على النحو المطلوب في ResizeObserver. لأنّ العرض المفرط قد يؤدي إلى ظهور حالات يصادف فيها المتصفّح يتأخر في القيام بالأعمال الهامة. على سبيل المثال، إذا كان أي تفاعل له تؤدي إلى تنفيذ معاودة الاتصال بالرمز ResizeObserver، تأكَّد من تنفيذ التالية لتسهيل الحصول على أفضل تجربة ممكنة:

  • تأكَّد من أنّ أدوات اختيار لغة CSS بسيطة قدر الإمكان لتجنّبها عملية إعادة احتساب النمط بشكل مفرط. تحدث عمليات إعادة حساب الأنماط قبل التنسيق مباشرةً، ويمكن لأدوات تحديد CSS المعقدة تأخير عمليات التخطيط.
  • تجنُّب تنفيذ أي عمل يمكن أن يؤدي إلى استدعاء ميزة "ResizeObserver" عمليات إعادة التدفق الإلزامية:
  • يزداد الوقت اللازم لتحديث تنسيق الصفحة بشكل عام مع عدد عناصر DOM في الصفحة. وعلى الرغم من أن ذلك يكون صحيحًا سواء كانت الصفحات تستخدم ResizeObserver، يمكن أن يصبح العمل المنجز في معاودة الاتصال على "ResizeObserver" أهمية مع زيادة التعقيد الهيكلي للصفحة.

الخاتمة

ResizeObserver متاح في جميع متصفِّحات وتوفر طريقة فعالة لمراقبة تغييرات حجم العناصر في أحد العناصر المستوى. عليك توخّي الحذر وعدم تأخير العرض كثيرًا باستخدام واجهة برمجة التطبيقات الفعّالة هذه.