بناء مكون نخب

نظرة عامة أساسية حول كيفية بناء مكوّن للخبز المحمّص التكيُّفي الذي يسهل الوصول إليه.

في هذه المشاركة، أود مشاركة التفكير حول كيفية بناء مكون نخب. ننصحك بالاطّلاع على العرض التوضيحي.

إصدار تجريبي

في ما يلي إصدار YouTube من هذه المشاركة إذا كنت تفضّل الفيديوهات:

نظرة عامة

إنّ إشعارات الخبز هي رسائل قصيرة غير تفاعلية وغير تفاعلية وغير متزامنة مخصصة للمستخدمين. تُستخدم بشكل عام كنمط لملاحظات الواجهة لإبلاغ المستخدم بنتائج إجراء ما.

التفاعلات

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

Markup

يُعد العنصر <output> اختيارًا جيدًا للخبز المحمّص لأنّه يتم عرضه لقرّاء الشاشة. يوفر لنا ترميز HTML الصحيح قاعدة آمنة لتحسينه باستخدام JavaScript وCSS، وسيتوفّر لنا الكثير من محتوى JavaScript.

الخبز المحمّص

<output class="gui-toast">Item added to cart</output>

يمكن أن تكون أكثر شمولية من خلال إضافة role="status". ويوفّر هذا الإجراء إجراءً احتياطيًا إذا لم يمنح المتصفّح عناصر <output> الدور الضمني وفقًا للمواصفات.

<output role="status" class="gui-toast">Item added to cart</output>

علبة الخبز المحمّص

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

<section class="gui-toast-group">
  <output role="status">Wizard Rose added to cart</output>
  <output role="status">Self Watering Pot added to cart</output>
</section>

التنسيقات

اخترتُ تثبيت نخب من inset-block-end على إطار العرض، وإذا أضفت المزيد من الخبز المحمّص، ستظهر من حافة الشاشة.

حاوية الفاتورة الرسمية الموحّدة

تقوم حاوية الخبز المحمص بجميع أعمال التخطيط لتقديم الخبز المحمص. وتكون القيمة fixed لإطار العرض واستخدام السمة المنطقية inset لتحديد الحواف التي يجب تثبيتها، بالإضافة إلى جزء صغير من padding من حافة block-end نفسها.

.gui-toast-group {
  position: fixed;
  z-index: 1;
  inset-block-end: 0;
  inset-inline: 0;
  padding-block-end: 5vh;
}

لقطة شاشة بحجم مربّع DevTools والمساحة المتروكة متراكبة على عنصر gui-toast-container.

بالإضافة إلى وضع نفسه داخل إطار العرض، فإنّ حاوية الخبز المحمّص هي حاوية شبكة يمكنها محاذاة الخبز المحمّص وتوزيعه. يتم توسيط العناصر كمجموعة تحتوي على justify-content ويتم توسيطها بشكل فردي باستخدام justify-items. أضِف القليل من gap حتى لا يلمس الخبز المحمّص.

.gui-toast-group {
  display: grid;
  justify-items: center;
  justify-content: center;
  gap: 1vh;
}

لقطة شاشة تعرض تراكب شبكة CSS على مجموعة الخبز المشترك، وتُبرز هذه المرة المساحة والثغرات بين العناصر الفرعية للخبز المحمّص.

الخبز المحمّص في واجهة المستخدم الرسومية

يحتوي الخبز المحمّص الفردي على padding، وبعض الزوايا ناعمة مع border-radius، ووظيفة min() للمساعدة في تحديد حجم الأجهزة الجوّالة والكمبيوتر المكتبي. يمنع الحجم سريع الاستجابة في CSS التالي زيادة عرض نخب بأكثر من 90% من إطار العرض أو 25ch.

.gui-toast {
  max-inline-size: min(25ch, 90vw);
  padding-block: .5ch;
  padding-inline: 1ch;
  border-radius: 3px;
  font-size: 1rem;
}

لقطة شاشة لعنصر .gui-toast واحد، مع إظهار مساحة متروكة ونصف قطر الحدود

الأنماط

باستخدام إعدادات التنسيق والموضع، يمكنك إضافة CSS التي تساعد في التكيف مع إعدادات المستخدم وتفاعلاته.

حاوية الخبز المحمّص

إشعارات الخبز ليست تفاعلية، فالنقر عليها أو التمرير فوقها لا يفعل أي شيء، لكنها تستخدم حاليًا أحداث المؤشر. امنع الخبز المحمّص من سرقة النقرات باستخدام خدمة CSS التالية.

.gui-toast-group {
  pointer-events: none;
}

الخبز المحمّص في واجهة المستخدم الرسومية

يمكنك تخصيص مظهر فاتح أو داكن تكيّفي للخبز المحمص مع خصائص مخصصة وHSL واستعلام عن وسائط مفضلة.

.gui-toast {
  --_bg-lightness: 90%;

  color: black;
  background: hsl(0 0% var(--_bg-lightness) / 90%);
}

@media (prefers-color-scheme: dark) {
  .gui-toast {
    color: white;
    --_bg-lightness: 20%;
  }
}

Animation

يجب أن يقدم الخبز المحمّص الجديد نفسه مع رسم متحرك عند دخوله إلى الشاشة. يتم توفير الحركة المخفّضة من خلال ضبط قيم translate على 0 تلقائيًا، مع تعديل قيمة الحركة إلى طول في طلب بحث وسائط مفضّلة للحركة . يحصل كل شخص على بعض الرسوم المتحركة، ولكن بعض المستخدمين فقط لديهم الخبز المحمّص مسافة.

في ما يلي الإطارات الرئيسية المستخدمة في الصورة المتحركة التي تعرض الخبز المحمّص. وستتحكم CSS في الدخول والانتظار والخروج من الخبز المحمّص، كل ذلك في صورة متحركة واحدة.

@keyframes fade-in {
  from { opacity: 0 }
}

@keyframes fade-out {
  to { opacity: 0 }
}

@keyframes slide-in {
  from { transform: translateY(var(--_travel-distance, 10px)) }
}

ومن ثم يعمل عنصر الإعلام المنبثق على إعداد المتغيرات وتنسيق الإطارات الرئيسية.

.gui-toast {
  --_duration: 3s;
  --_travel-distance: 0;

  will-change: transform;
  animation: 
    fade-in .3s ease,
    slide-in .3s ease,
    fade-out .3s ease var(--_duration);
}

@media (prefers-reduced-motion: no-preference) {
  .gui-toast {
    --_travel-distance: 5vh;
  }
}

JavaScript

نظرًا إلى تجهيز الأنماط ولغة HTML التي يمكن الوصول إليها من خلال قارئ الشاشة، تكون هناك حاجة إلى JavaScript لتنسيق عملية إنشاء نخب محمّص وإضافتها وإتلافها استنادًا إلى أحداث المستخدم. يجب أن تكون تجربة المطور لمكون الخبز المحمّص بسيطة ويسهل البدء بها، كما يلي:

import Toast from './toast.js'

Toast('My first toast')

إنشاء مجموعة الخبز المحمص ونخب

عند تحميل وحدة الإبلاغ عن المحتوى من JavaScript، يجب إنشاء حاوية نخب وإضافتها إلى الصفحة. لقد اخترت إضافة العنصر قبل body، وسيؤدي ذلك إلى احتمال حدوث z-index مشكلة في تكديس لأنّ الحاوية أعلى الحاوية لجميع عناصر النص الأساسي.

const init = () => {
  const node = document.createElement('section')
  node.classList.add('gui-toast-group')

  document.firstElementChild.insertBefore(node, document.body)
  return node
}

لقطة شاشة لمجموعة الخبز المحمّص بين الرأس وعلامات الجسم

يتم استدعاء الدالة init() داخليًا إلى الوحدة النمطية، وتخزين العنصر في شكل Toaster:

const Toaster = init()

يتم إنشاء عنصر HTML للنبيذ باستخدام الدالة createToast(). تتطلب الدالة بعض النص للخبز المحمّص، وتنشئ عنصر <output>، وتزيّنه ببعض الفئات والسمات، وتعين النص، وتُرجع العقدة.

const createToast = text => {
  const node = document.createElement('output')
  
  node.innerText = text
  node.classList.add('gui-toast')
  node.setAttribute('role', 'status')

  return node
}

إدارة رسالة نخب واحدة أو أكثر

تضيف لغة JavaScript الآن حاوية إلى المستند لتحتوي على نخب، وهي جاهزة لإضافة نخب تم إنشاؤها. تتولى الدالة addToast() تنسيق عملية التعامل مع نخب واحد أو أكثر. يتم أولاً التحقق من عدد الخبز المحمّص، والتأكد مما إذا كانت الحركة على ما يرام، ثم استخدام هذه المعلومات لإضافة الخبز المحمّص أو إنشاء بعض الرسوم المتحركة الرائعة حتى يبدو أن الخبز المحمّص الآخر "يفسح المجال" للخبز المحمّص الجديد.

const addToast = toast => {
  const { matches:motionOK } = window.matchMedia(
    '(prefers-reduced-motion: no-preference)'
  )

  Toaster.children.length && motionOK
    ? flipToast(toast)
    : Toaster.appendChild(toast)
}

عند إضافة أول نخب محمّص، يضيف Toaster.appendChild(toast) نخبًا إلى الصفحة، ما يؤدي إلى ظهور الصور المتحركة في CSS: إضافة "تحريك" و"انتظار 3s" و"تحريك". يتم استدعاء flipToast() عند توفّر نخب محمّص حاليًا، وذلك باستخدام تقنية تُعرف باسم FLIP من قِبل بول لويس. والفكرة هي حساب الفرق في مواضع الوعاء، قبل إضافة الخبز المحمّص الجديد وبعده. فكر في الأمر كأنه تحديد أين يوجد محمصة الخبز الآن، وأين ستكون، ثم الرسوم المتحركة من حيث كانت إلى مكانها.

const flipToast = toast => {
  // FIRST
  const first = Toaster.offsetHeight

  // add new child to change container size
  Toaster.appendChild(toast)

  // LAST
  const last = Toaster.offsetHeight

  // INVERT
  const invert = last - first

  // PLAY
  const animation = Toaster.animate([
    { transform: `translateY(${invert}px)` },
    { transform: 'translateY(0)' }
  ], {
    duration: 150,
    easing: 'ease-out',
  })
}

تؤدي شبكة CSS إلى تحسين التصميم. عند إضافة نخب جديد، تضعه الشبكة في البداية وتتباعده مع الأخرى. وفي الوقت نفسه، يتم استخدام صورة متحركة على الويب لتحريك الحاوية من موضعها القديم.

دمج كل رموز JavaScript

عند استدعاء Toast('my first toast')، يتم إنشاء نخب وتضيفه إلى الصفحة (ربما يتم تحريك الحاوية حتى تتسع للخبز المحمّص الجديد)، ويتم عرض وعد، ويتم مشاهدة الإشعار المنبثق الذي تم إنشاؤه لاكتمال صور متحركة في CSS (الصور المتحركة الثلاثة للإطارات الرئيسية) للحصول على درجة الدقة المطلوبة.

const Toast = text => {
  let toast = createToast(text)
  addToast(toast)

  return new Promise(async (resolve, reject) => {
    await Promise.allSettled(
      toast.getAnimations().map(animation => 
        animation.finished
      )
    )
    Toaster.removeChild(toast)
    resolve() 
  })
}

شعرتُ أن الجزء المحير من هذا الرمز البرمجي موجود في دالة Promise.allSettled() وربط toast.getAnimations(). بما أنني استخدمت العديد من الصور المتحركة في الإطارات الرئيسية لتشغيل الخبز المحمّص، أعرف بثقة أنّ جميع هذه اللقطات قد انتهت، لذا يجب طلب كل منها من JavaScript وأنّ كل وعود من finished تتم ملاحظتها باكتمالها. إنّ allSettled هذا مفيد بالنسبة إلينا، حيث يتبيّن لنا أنّه مكتملة بعد الوفاء بجميع وعوده. يعني استخدام await Promise.allSettled() أن السطر التالي من التعليمات البرمجية يمكنه إزالة العنصر بثقة وافتراض اكتمال دورة حياة الخبز المحمّص. وأخيرًا، يلبّي استدعاء resolve() وعد Toast العالي المستوى، حتى يتمكّن المطوّرون من حذف البرامج غير المرغوب فيها أو تنفيذ أي مهام أخرى بعد عرض الإشعار.

export default Toast

أخيرًا، يتم تصدير الدالة Toast من الوحدة النمطية، وذلك لاستيراد النصوص البرمجية الأخرى واستخدامها.

استخدام مكوِّن Toast

يتم استخدام إشعار التحمّص أو تجربة المطوّر في نموذج الخبز المحمّص من خلال استيراد دالة Toast واستدعائها باستخدام سلسلة رسالة.

import Toast from './toast.js'

Toast('Wizard Rose added to cart')

إذا أراد مطوّر البرامج تنفيذ مهام تنظيف البيانات أو إنجاز تلك المهام، يمكنه استخدام وضع "المزامنة" وawait بعد ظهور إشعار "الإشعار المدفوع".

import Toast from './toast.js'

async function example() {
  await Toast('Wizard Rose added to cart')
  console.log('toast finished')
}

الخلاصة

الآن بعد أن عرفت كيف فعلت ذلك، كيف يمكنك‽ 🙂

دعونا ننويع أساليبنا ونتعلم جميع طرق الإنشاء على الويب. يمكنك إنشاء عرض توضيحي وروابط تغريدات لي وسنضيفها إلى قسم الريمكسات في المنتدى أدناه.

ريمكسات من المنتدى