مكوّنات طريقة التنفيذ - مربّع اختيار طريقة التنفيذ

ملخّص

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

يحاول العنصر تطبيق السمتين role="checkbox" بشكل ذاتي tabindex="0" عند إنشائه لأول مرة. تساعد السمة role تقنية مثل قارئ الشاشة تخبر المستخدم عن نوع التحكم هذا. تعمل السمة tabindex على تفعيل العنصر في ترتيب التنقل بـ Tab، مما يجعله لوحة المفاتيح وقابلة للتركيز والتشغيل. لمعرفة المزيد حول هذين الموضوعين، اطلع على ما الذي يمكن أن يفعله ARIA؟ واستخدام tabindex

عند وضع علامة في مربّع الاختيار، تضيف السمة المنطقية checked وتضبط قيمة السمة checked المقابلة لـ true. بالإضافة إلى ذلك، يعين العنصر سمة aria-checked إما إلى "true" أو "false"، بناءً على الولاية. يؤدي النقر على مربع الاختيار بالماوس أو شريط المسافة إلى تبديل هذه الحالات المحددة.

يتيح مربّع الاختيار أيضًا استخدام حالة disabled. إذا كانت السمة disabled على "صحيح" أو عند تطبيق السمة disabled، فستُضبط مربّعات الاختيار aria-disabled="true"، وتتم إزالة السمة tabindex وإعادة التركيز بالمستند إذا كان مربّع الاختيار هو activeElement الحالي.

يتم إقران مربّع الاختيار بعنصر howto-label للتأكّد من أنّه يتضمّن اسم ظاهر.

مَراجع

عرض توضيحي

مشاهدة عرض توضيحي مباشر على GitHub

مثال على الاستخدام

<style>
  howto-checkbox {
    vertical-align: middle;
  }
  howto-label {
    vertical-align: middle;
    display: inline-block;
    font-weight: bold;
    font-family: sans-serif;
    font-size: 20px;
    margin-left: 8px;
  }
</style>

<howto-checkbox id="join-checkbox"></howto-checkbox>
<howto-label for="join-checkbox">Join Newsletter</howto-label>

الرمز

(function() {

يمكنك تحديد رموز رئيسية للمساعدة في التعامل مع أحداث لوحة المفاتيح.

  const KEYCODE = {
    SPACE: 32,
  };

يُعدّ استنساخ المحتوى من عنصر <template> أفضل من استخدام HTML الداخلي لأنّه يتجنّب التكاليف الإضافية لتحليل HTML.

  const template = document.createElement('template');

  template.innerHTML = `
    <style>
      :host {
        display: inline-block;
        background: url('../images/unchecked-checkbox.svg') no-repeat;
        background-size: contain;
        width: 24px;
        height: 24px;
      }
      :host([hidden]) {
        display: none;
      }
      :host([checked]) {
        background: url('../images/checked-checkbox.svg') no-repeat;
        background-size: contain;
      }
      :host([disabled]) {
        background:
          url('../images/unchecked-checkbox-disabled.svg') no-repeat;
        background-size: contain;
      }
      :host([checked][disabled]) {
        background:
          url('../images/checked-checkbox-disabled.svg') no-repeat;
        background-size: contain;
      }
    </style>
  `;


  class HowToCheckbox extends HTMLElement {
    static get observedAttributes() {
      return ['checked', 'disabled'];
    }

يتم تشغيل الدالة الإنشائية للعنصر في أي وقت يتم فيه إنشاء مثيل جديد. يتم إنشاء المثيلات إما عن طريق تحليل HTML أو استدعاء document.createElement('howto-checkbox') أو استدعاء HowToCheckbox(); تعتبر الدالة الإنشائية مكانًا جيدًا لإنشاء shadow DOM، على الرغم من أنّه يجب تجنُّب لمس أي سمات أو عناصر light DOM الثانوية لأنّها قد لا تكون متاحة بعد.

    constructor() {
      super();
      this.attachShadow({mode: 'open'});
      this.shadowRoot.appendChild(template.content.cloneNode(true));
    }

يتم تنشيط connectedCallback() عند إدراج العنصر في DOM. وهو مكان مناسب لضبط أدوات معالجة الأحداث المبدئية في role وtabindex والحالة الداخلية وعمليات التثبيت.

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

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

      this._upgradeProperty('checked');
      this._upgradeProperty('disabled');

      this.addEventListener('keyup', this._onKeyUp);
      this.addEventListener('click', this._onClick);
    }

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

يتم تنشيط disconnectedCallback() عند إزالة العنصر من DOM. إنه مكان جيد لإنجاز الأعمال مثل إصدار المراجع وإزالة المستمعين للأحداث.

    disconnectedCallback() {
      this.removeEventListener('keyup', this._onKeyUp);
      this.removeEventListener('click', this._onClick);
    }

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

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

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

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

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

يتم استدعاء attributeChangedCallback() عند تغيير أي من السمات في صفيف noticeAttributes. وهو مكان جيد للتعامل مع الآثار الجانبية، مثل ضبط سمات ARIA.

    attributeChangedCallback(name, oldValue, newValue) {
      const hasValue = newValue !== null;
      switch (name) {
        case 'checked':
          this.setAttribute('aria-checked', hasValue);
          break;
        case 'disabled':
          this.setAttribute('aria-disabled', hasValue);

لا توفّر السمة tabindex طريقة لإلغاء إمكانية التركيز بالكامل من العنصر. سيظلّ بإمكانك التركيز على العناصر التي تتضمّن tabindex=-1 باستخدام الماوس أو من خلال طلب القيمة focus(). للتأكّد من إيقاف عنصر ومن عدم إمكانية التركيز عليه، أزِل السمة tabindex.

          if (hasValue) {
            this.removeAttribute('tabindex');

إذا كان التركيز حاليًا على هذا العنصر، يجب إلغاء التركيز عن طريق استدعاء طريقة HTMLElement.blur()

            this.blur();
          } else {
            this.setAttribute('tabindex', '0');
          }
          break;
      }
    }

    _onKeyUp(event) {

لا تتعامل مع اختصارات المعدِّل التي تستخدمها عادةً التكنولوجيا المساعِدة.

      if (event.altKey)
        return;

      switch (event.keyCode) {
        case KEYCODE.SPACE:
          event.preventDefault();
          this._toggleChecked();
          break;

ويتم تجاهل أي ضغطة مفتاحية أخرى وإعادتها إلى المتصفِّح.

        default:
          return;
      }
    }

    _onClick(event) {
      this._toggleChecked();
    }

يستدعي _toggleChecked() الإعداد المحدّد ويقلب حالته. بما أنّ _toggleChecked() ناتج عن إجراء من جانب المستخدم فقط، سيتم أيضًا إرسال حدث تغيير. يظهر هذا الحدث كفقاعات لمحاكاة سلوك <input type=checkbox> الأصلي.

    _toggleChecked() {
      if (this.disabled)
        return;
      this.checked = !this.checked;
      this.dispatchEvent(new CustomEvent('change', {
        detail: {
          checked: this.checked,
        },
        bubbles: true,
      }));
    }
  }

  customElements.define('howto-checkbox', HowToCheckbox);
})();