أفضل الممارسات المتعلقة بالعناصر المخصّصة

تتيح لك العناصر المخصصة إنشاء علامات HTML الخاصة بك. تتناول قائمة التحقق هذه أفضل الممارسات لمساعدتك في إنشاء عناصر عالية الجودة.

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

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

قائمة التحقق

نموذج Shadow DOM

إنشاء جذر ظل لتغليف الأنماط.

لماذا؟ يضمن تغليف الأنماط في جذور الظل للعنصر نجاحها بغض النظر عن مكان استخدامها. هذا مهم بشكل خاص إذا كان مطور يريد وضع العنصر داخل جذر الظل لعنصر آخر. هذا النمط وينطبق على العناصر البسيطة مثل مربع الاختيار أو زر الاختيار. قد يكون إذا كان المحتوى الوحيد داخل جذر الظل هو الأنماط أنفسهم.
مثال صفحة العنصر <howto-checkbox>.

أنشئ جذر الظل في الدالة الإنشائية.

لماذا؟ دالة الإنشاء هي عندما تتوفر لديك معرفة حصرية للعنصر. هذا هو الوقت المناسب لإعداد تفاصيل التنفيذ التي لا تريدها أن العناصر المختلفة. ويؤدي هذا الإجراء إلى معاودة الاتصال لاحقًا، مثل connectedCallback، يعني أنك ستحتاج إلى الاحتراس من الحالات التي يتم فيها فصل العنصر ثم إعادة إرفاقه بالمستند.
مثال صفحة العنصر <howto-checkbox>.

ضع أي عناصر فرعية ينشئها العنصر في جذور الظل.

لماذا؟ العناصر الثانوية التي ينشئها العنصر هي جزء من تنفيذه ويجب أن تكون خاصة. بدون حماية جذر الظل، قد تتوفر خارج JavaScript وتتدخل بدون قصد في هؤلاء الأطفال.
مثال صفحة العنصر <howto-tabs>.

استخدام <slot> لإسقاط عناصر light DOM في shadow DOM

لماذا؟ السماح لمستخدمي المكوِّن بتحديد المحتوى فيه حيث إن عناصر HTML الثانوية تجعل المكون أكثر قابلية للإنشاء. عندما لا يتيح المتصفح استخدام العناصر المخصصة، يظل المحتوى المتداخل متاحًا ومرئيًا ويمكن الوصول إليه.
مثال صفحة العنصر <howto-tabs>.

ضبط نمط عرض :host (مثل block، inline-block، flex) إلا إذا كنت تفضل الإعداد التلقائي inline

لماذا؟ العناصر المخصّصة هي display: inline تلقائيًا، لذا فإنّ ضبط ولن يكون لـ width أو height أي تأثير. هذا غالبًا يُعد مفاجأة للمطورين وقد يتسبب في حدوث مشكلات تتعلق تخطيط الصفحة. ما لم تكن تفضل شاشة inline، يمكنك يجب أن تضبط دائمًا قيمة display تلقائية.
مثال صفحة العنصر <howto-checkbox>.

أضِف نمط عرض :host يلتزم بالسمة المخفية.

لماذا؟ عنصر مخصص بنمط display تلقائي، على سبيل المثال: سيؤدي الخيار :host { display: block } إلى إلغاء مستوى الدقة الأقل. مدمج hidden. قد يفاجئك هذا إذا كنت تتوقع ضبط hidden. على العنصر ليتم عرضه display: none. بالإضافة إلى ذلك إلى نمط display التلقائي، إضافة التوافق مع hidden مع :host([hidden]) { display: none }.
مثال صفحة العنصر <howto-checkbox>.

السمات والخصائص

لا تتجاهل السمات العامة التي حدّدها المؤلف.

لماذا؟ السمات العامة هي تلك الموجودة في جميع عناصر HTML. بعض الإشعارات تشمل الأمثلة tabindex وrole. عنصر مخصص قد ترغب في ضبط tabindex الأولى على 0 بحيث تكون لوحة المفاتيح يمكن التركيز عليه. ولكن يجب عليك دائمًا التحقق أولاً لمعرفة ما إذا كان المطور يستخدم قام عنصرك بتعيين هذا على قيمة أخرى. على سبيل المثال، إذا قاموا بتعيين tabindex إلى -1، فهذه إشارة إلى عدم رغبتهم في أن يكون تفاعليًا.
مثال صفحة العنصر <howto-checkbox>. سيتم توضيح ذلك بمزيد من التفصيل في لا تتجاهل مؤلف الصفحة.

قبول البيانات الأولية (السلاسل والأرقام والقيم المنطقية) كسمتين دائمًا أو الخصائص.

لماذا؟ يجب أن تكون العناصر المخصصة، مثل نظيراتها المضمَّنة، قابلة للتهيئة. يمكن تمرير التهيئة بيانًا، عبر السمات، أو ضروريًا عبر سمات JavaScript من الناحية المثالية، يجب أيضًا ربط كل سمة لموقع مطابق.
مثال صفحة العنصر <howto-checkbox>.

تهدف إلى الحفاظ على مزامنة سمات وخصائص البيانات الأساسية، مما يعكس من إلى الإحالة، والعكس صحيح.

لماذا؟ أنت لا تعرف أبدًا كيف سيتفاعل المستخدم مع العنصر الخاص بك. ربما تعيين خاصية في JavaScript، ثم نتوقع قراءة تلك القيمة باستخدام واجهة برمجة تطبيقات مثل getAttribute(). فإذا كانت كل سمة لها الخاص بها، وكلاهما يعكس، أن ذلك سيسهل على المستخدمين للعمل على العنصر الخاص بك. بمعنى آخر، يؤدي الاتصال يجب أيضًا على setAttribute('foo', value) تحديد قيمة foo والعكس صحيح. هناك بالطبع استثناءات هذه القاعدة. يجب ألا تعكس خصائص معدل التكرار المرتفع، مثل currentTime في مشغّل الفيديو. استخدِم أفضل تقدير لك. إذا كان ويبدو أن المستخدم سيتفاعل مع خاصية أو سمة، فليس من الصعب إظهار ذلك، إذًا
مثال صفحة العنصر <howto-checkbox>. سيتم توضيح ذلك بمزيد من التفصيل في تجنُّب مشاكل إعادة الدخول:

ركِّز على قبول البيانات المنسّقة (الكائنات والصفائف) فقط كسمات.

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

لا تعكس خصائص البيانات الغنية بصريًا للسمات.

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

ننصحك بالتحقق من الخصائص التي يُحتمل أنّها مضبوطة قبل العنصر التي تمت ترقيتها.

لماذا؟ قد يحاول أحد مطوّري البرامج الذين يستخدمون العنصر تعيين خاصية لهذا العنصر. قبل تحميل تعريفه. هذا صحيح بشكل خاص إذا تم يستخدم مطور البرامج إطار عمل يعالج مكونات التحميل ويختمها بالصفحة، وربط خصائصها بنموذج.
مثال صفحة العنصر <howto-checkbox>. مزيد من التوضيح في جعل المواقع كسولة:

لا تطبِّق الدروس ذاتيًا.

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

فعاليات

إرسال الأحداث استجابةً لنشاط المكوّنات الداخلية.

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

لا ترسِل الأحداث استجابةً لإعداد المضيف لخاصية (إلى أسفل). تدفق البيانات).

لماذا؟ يعتبر إرسال حدث استجابةً لإعداد المضيف (خاصية) أمرًا غير ضروري (يعرف المضيف الحالة الحالية لأنه تم تعيينها للتو). إرسال الأحداث استجابةً لإعداد المضيف، قد تتسبب خاصية في تكرارات لانهائية مع البيانات وأنظمة الربط.
مثال صفحة العنصر <howto-checkbox>.

تفسيرات

عدم تجاوز مؤلف الصفحة

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

connectedCallback() {
  if (!this.hasAttribute('role'))
    this.setAttribute('role', 'checkbox');
  if (!this.hasAttribute('tabindex'))
    this.setAttribute('tabindex', 0);

تفعيل الوضع "كسول" في المواقع

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

في المثال التالي، تُجري Angular ربط نموذجها صراحةً isChecked إلى السمة checked في مربّع الاختيار. إذا كان تعريف طريقة التحميل الكسول في مربّع الاختيار، فمن المحتمل أن يحاول Angular ضبط الخاصية المحددة قبل ترقية العنصر.

<howto-checkbox [checked]="defaults.isChecked"></howto-checkbox>

يجب أن يتعامل عنصر مخصص مع هذا السيناريو عن طريق التحقق مما إذا كانت أي خصائص تحتوي على بالفعل على المثيل الخاص به. <howto-checkbox> توضح هذا النمط باستخدام طريقة تسمى _upgradeProperty().

connectedCallback() {
  ...
  this._upgradeProperty('checked');
}

_upgradeProperty(prop) {
  if (this.hasOwnProperty(prop)) {
    let value = this[prop];
    delete this[prop];
    this[prop] = value;
  }
}

يلتقط _upgradeProperty() القيمة من المثيل الذي لم تتم ترقيته ويحذفه. الخاصية بحيث لا تظلل أداة تحديد الخصائص الخاصة بالعنصر المخصّص. بهذه الطريقة، عندما يتم تحميل تعريف العنصر أخيرًا، يمكن فورًا تعكس الحالة الصحيحة.

تجنُّب مشاكل إعادة الدخول

من المغري استخدام attributeChangedCallback() لتعكس الحالة الموقع الأساسي، مثل:

// When the [checked] attribute changes, set the checked property to match.
attributeChangedCallback(name, oldValue, newValue) {
  if (name === 'checked')
    this.checked = newValue;
}

ولكن هذا يمكن أن ينشئ تكرارًا لا نهائي إذا انعكست دالة setter أيضًا على السمة.

set checked(value) {
  const isChecked = Boolean(value);
  if (isChecked)
    // OOPS! This will cause an infinite loop because it triggers the
    // attributeChangedCallback() which then sets this property again.
    this.setAttribute('checked', '');
  else
    this.removeAttribute('checked');
}

البديل هو السماح لدالة setter بالانعكاس على السمة، يحدد دالة getter قيمته بناءً على التصنيف.

set checked(value) {
  const isChecked = Boolean(value);
  if (isChecked)
    this.setAttribute('checked', '');
  else
    this.removeAttribute('checked');
}

get checked() {
  return this.hasAttribute('checked');
}

في هذا المثال، ستؤدي إضافة السمة أو إزالتها إلى تحديد السمة أيضًا.

أخيرًا، يمكن استخدام attributeChangedCallback() لمعالجة الآثار الجانبية. مثل تطبيق حالات ARIA.

attributeChangedCallback(name, oldValue, newValue) {
  const hasValue = newValue !== null;
  switch (name) {
    case 'checked':
      // Note the attributeChangedCallback is only handling the *side effects*
      // of setting the attribute.
      this.setAttribute('aria-checked', hasValue);
      break;
    ...
  }
}