النموذج والخانة والظل

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

يتكون معيار مكوّن الويب من ثلاثة أجزاء - نماذج HTML العناصر المخصّصة وShadow DOM. وتتيح الخوارزمية معًا إنشاء عناصر مخصّصة ومستقلة (مغلَّفة) وقابلة لإعادة الاستخدام ويمكن دمجها بسلاسة. مع التطبيقات الحالية، مثل جميع عناصر HTML الأخرى التي تناولناها بالفعل.

في هذا القسم، سننشئ العنصر <star-rating>، وهو مكوّن ويب يتيح للمستخدمين تقييم تجربة على مقياس من نجمة واحدة إلى خمس نجوم. عند تسمية عنصر مخصص، يُنصح باستخدام جميع الأحرف الصغيرة. أيضًا، قم بتضمين شرطة، حيث يساعد ذلك في التمييز بين العناصر العادية والمخصصة.

سنناقش استخدام العناصر <template> و<slot> والسمة slot وJavaScript لإنشاء نموذج باستخدام عنصر Shadow DOM مغلف. سنقوم بعد ذلك بإعادة استخدام العنصر المحدد، وتخصيص قسم من النص، مثلما تفعل مع أي عنصر أو مكوّن ويب. سنناقش أيضًا بإيجاز استخدام CSS من داخل العنصر المخصص وخارجه.

العنصر <template>

يُستخدَم العنصر <template> للإشارة إلى أجزاء HTML المراد استنساخها وإدراجها في DOM باستخدام JavaScript. لا يتم عرض محتوى العنصر بشكل تلقائي. وبدلاً من ذلك، يتم إنشاء مثيل لها باستخدام JavaScript.

<template id="star-rating-template">
  <form>
    <fieldset>
      <legend>Rate your experience:</legend>
      <rating>
        <input type="radio" name="rating" value="1" aria-label="1 star" required />
        <input type="radio" name="rating" value="2" aria-label="2 stars" />
        <input type="radio" name="rating" value="3" aria-label="3 stars" />
        <input type="radio" name="rating" value="4" aria-label="4 stars" />
        <input type="radio" name="rating" value="5" aria-label="5 stars" />
      </rating>
    </fieldset>
    <button type="reset">Reset</button>
    <button type="submit">Submit</button>
  </form>
</template>

لا يتم عرض محتوى عنصر <template> على الشاشة لأنّ <form> لا يظهر ومحتواه. نعم، رمز Codep هذا فارغ، ولكن إذا فحصت علامة تبويب HTML، سيظهر لك ترميز <template>.

في هذا المثال، لا يعتبر <form> عنصرًا فرعيًا من <template> في DOM. بدلاً من ذلك، يشتمل محتوى عناصر <template> على عناصر ثانوية DocumentFragment التي تم إرجاعها من خلال HTMLTemplateElement.content الموقع. لإظهار المحتوى، يجب استخدام JavaScript لجلب المحتوى وإلحاقه بنموذج DOM.

لم تُنشئ لغة JavaScript المختصرة عنصرًا مخصّصًا. بدلاً من ذلك، ألحَق هذا المثال محتوى <template> في <body>. وأصبح المحتوى جزءًا من نموذج العناصر في المستند (DOM) المرئي والقابل للأسلوب.

لقطة شاشة لبرنامج الترميز السابق كما هو موضّح في نموذج كائن المستند (DOM).

إن مطالبة JavaScript بتنفيذ نموذج لتقييم نجمة واحدة فقط ليس مفيدًا للغاية، ولكن إنشاء مكون ويب الأداة المستخدَمة بشكل متكرّر والقابلة للتخصيص بالنجوم مفيدة.

العنصر <slot>

ندرج خانة لتضمين وسيلة إيضاح مخصصة لكل موضع. يوفّر HTML السمة <slot> عنصر نائب أو عنصر نائب داخل <template> يؤدي إلى إنشاء "خانة مُسمّاة" في حال توفير اسم. يمكن استخدام خانة مُسَمّاة لتخصيص المحتوى داخل أحد مكونات الويب. يمنحنا العنصر <slot> طريقةً للتحكم في العناصر الثانوية الخاصة إدراج عنصر داخل شجرة الظل الخاصة به.

في النموذج، نُغيّر <legend> إلى <slot>:

<template id="star-rating-template">
  <form>
    <fieldset>
      <slot name="star-rating-legend">
        <legend>Rate your experience:</legend>
      </slot>

يتم استخدام السمة name لتعيين خانات لعناصر أخرى إذا كان العنصر يتضمن السمة slot التي تتطابق قيمتها مع اسم خانة مُعنوَنة. في حال عدم تطابق العنصر المخصّص مع خانة، سيتم عرض محتوى <slot>. لهذا السبب، أدرجنا <legend> مع محتوى عام يمكن عرضه إذا أدرج أي مستخدم السمة <star-rating></star-rating> بدون أي محتوى في HTML.

<star-rating>
  <legend slot="star-rating-legend">Blendan Smooth</legend>
</star-rating>
<star-rating>
  <legend slot="star-rating-legend">Hoover Sukhdeep</legend>
</star-rating>
<star-rating>
  <legend slot="star-rating-legend">Toasty McToastface</legend>
  <p>Is this text visible?</p>
</star-rating>

السمة slot هي سمة عمومية يتم استخدامها لاستبدال محتوى <slot> في <template>. في العنصر المخصص الخاص بنا، يكون العنصر الذي يتضمن سمة الفتحة هي <legend>. لا داعي للقلق. في النموذج، سيتم استبدال <slot name="star-rating-legend"> بـ <anyElement slot="star-rating-legend">، حيث يمكن أن يكون <anyElement> أي عنصر، حتى عنصرًا مخصصًا آخر.

عناصر غير محددة

في <template>، استخدمنا العنصر <rating>. هذا ليس عنصرًا مخصصًا. إنه عنصر غير معروف. المتصفّحات لا تفشل عندما لا تتعرف على عنصر ما. يتعامل المتصفّح مع عناصر HTML غير المعروفة على أنّها مضمّنة مجهولة. العناصر التي يمكن تصميمها باستخدام CSS. على غرار <span>، لا يتم تطبيق أي وكيل مستخدم في العنصرَين <rating> و<star-rating>. الأنماط أو الدلالات.

يُرجى العلم أنّه لا يتم عرض <template> والمحتوى. <template> هو عنصر معروف يتضمّن محتوى لن يتم عرضه. لم يتم بعد تحديد العنصر <star-rating>. حتى نحدد عنصرًا، يعرضه المتصفح مثل جميع العناصر غير المعروفة. في الوقت الحالي، يتم التعامل مع <star-rating> غير المعروف كعنصر مضمّن مجهول، وبالتالي فإن المحتوى بما في ذلك وسائل الإيضاح و<p> في السمة <star-rating> الثالثة، يتم عرضها كما كانت إذا كانت في <span> بدلاً من ذلك.

لنُعرف العنصر الخاص بنا لتحويل هذا العنصر غير المعروف إلى عنصر مخصص.

العناصر المخصصة

يجب توفّر JavaScript لتحديد العناصر المخصّصة. سيتم استبدال محتوى العنصر <star-rating> عند تحديده جذر الظل الذي يحتوي على جميع محتويات النموذج الذي نربطه به. تم استبدال عناصر <slot> من النموذج. يشتمل على محتوى العنصر في <star-rating> الذي تتطابق قيمة سمة slot فيه مع قيمة اسم <slot>، إذا واحد. وإذا لم يكن الأمر كذلك، سيتم عرض محتوى خانات النموذج.

لا يتم تضمين المحتوى المتوفر داخل عنصر مخصص غير مرتبط بخانة، مثل <p>Is this text visible?</p> في <star-rating> الثالث، في جذر الظل وبالتالي لا يتم عرضه.

نعرّف العنصر المخصص باسم star-rating من خلال تمديد HTMLElement:

customElements.define('star-rating',
  class extends HTMLElement {
    constructor() {
      super(); // Always call super first in constructor
      const starRating = document.getElementById('star-rating-template').content;
      const shadowRoot = this.attachShadow({
        mode: 'open'
      });
      shadowRoot.appendChild(starRating.cloneNode(true));
    }
  });

بعد أن تم تحديد العنصر، سيتم عرضه على النحو المحدّد في كل مرة يصادف فيها المتصفّح عنصر <star-rating>. بجانب العنصر مع #star-rating-template، وهو النموذج الخاص بنا. سيرفق المتصفح شجرة shadow DOM بالعقدة، ملحقًا نسخة طبق الأصل من محتوى النموذج إلى shadow DOM هذا. يُرجى العِلم أنّ العناصر التي يمكنك attachShadow() الاعتماد عليها محدودة.

const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(starRating.cloneNode(true));

إذا ألقيت نظرة على أدوات المطوّرين، ستلاحظ أن <form> من <template> هو جزء من جذر الظل لكل عنصر مخصّص. يظهر نسخة طبق الأصل من محتوى "<template>" في كل عنصر مخصّص ضمن أدوات المطوّرين، كما يظهر في المتصفّح، ولكن لا يُظهر المحتوى. العنصر المخصص نفسه لا يتم عرضه على الشاشة.

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

في المثال <template>، ألحقنا محتوى النموذج بنص المستند، ونضيف المحتوى إلى نموذج DOM العادي. في تعريف customElements، استخدمنا نفس appendChild()، ولكن تم إلحاق محتوى النموذج المنسوخ نص shadow DOM المغلف.

هل لاحظت كيف عادت النجوم إلى استخدام أزرار اختيار بلا نمط؟ وكونه جزءًا من shadow DOM بدلاً من DOM العادي، لا ينطبق النمط داخل علامة تبويب CSS في Codepen. CSS في علامة التبويب هذه يتم تحديد الأنماط على المستند، وليس على shadow DOM، لذلك لا يتم تطبيق الأنماط. ينبغي أن ننشئ قيمًا مغلفة لتصميم محتوى Shadow DOM المغلّف.

نموذج Shadow DOM

يحدد Shadow DOM أنماط CSS لكل شجرة ظل، مع عزلها عن باقي المستند. يشير ذلك إلى خدمة CSS خارجية. لا تنطبق على المكون، ولن تؤثر أنماط المكوّنات على باقي المستند، ما لم نقصد توجيههم إليه.

يمكننا تضمين العنصر <style> لأنّنا ألحقنا المحتوى في shadow DOM توفير CSS مغلف للعنصر المخصص.

نظرًا لاستخدام العنصر المخصص، لا داعي للقلق بشأن ظهور الأنماط في باقي المستند. يمكننا تقليل خصوصية المحددات بشكل كبير. على سبيل المثال، نظرًا لأن المدخلات الوحيدة المستخدمة في العنصر المخصص هي الراديو يمكننا استخدام input بدلاً من input[type="radio"] كأداة اختيار.

 <template id="star-rating-template">
  <style>
    rating {
      display: inline-flex;
    }
    input {
      appearance: none;
      margin: 0;
      box-shadow: none;
    }
    input::after {
      content: '\2605'; /* solid star */
      font-size: 32px;
    }
    rating:hover input:invalid::after,
    rating:focus-within input:invalid::after {
      color: #888;
    }
    input:invalid::after,
      rating:hover input:hover ~ input:invalid::after,
      input:focus ~ input:invalid::after  {
      color: #ddd;
    }
    input:valid {
      color: orange;
    }
    input:checked ~ input:not(:checked)::after {
      color: #ccc;
      content: '\2606'; /* hollow star */
    }
  </style>
  <form>
    <fieldset>
      <slot name="star-rating-legend">
        <legend>Rate your experience:</legend>
      </slot>
      <rating>
        <input type="radio" name="rating" value="1" aria-label="1 star" required/>
        <input type="radio" name="rating" value="2" aria-label="2 stars"/>
        <input type="radio" name="rating" value="3" aria-label="3 stars"/>
        <input type="radio" name="rating" value="4" aria-label="4 stars"/>
        <input type="radio" name="rating" value="5" aria-label="5 stars"/>
      </rating>
    </fieldset>
    <button type="reset">Reset</button>
    <button type="submit">Submit</button>
  </form>
</template>

فيما يتم تغليف مكونات الويب باستخدام الترميز in-<template> ويتم تحديد أنماط CSS إلى shadow DOM وإخفاءها من كل العناصر خارج المكوّنات، ومحتوى الخانة الذي يتم عرضه، و<anyElement slot="star-rating-legend"> الجزء من <star-rating> غير مغلف.

التصميم خارج النطاق الحالي

من الممكن، ولكن ليس من السهل، تصميم نمط المستند من داخل shadow DOM وإنشاء محتوى في shadow DOM من الأنماط العالمية. يمكن اجتياز حدود الظل، حيث ينتهي shadow DOM ويبدأ DOM العادي، ولكن فقط عن قصد للغاية.

شجرة الظل هي شجرة نموذج العناصر في المستند (DOM) داخل shadow DOM. جذر الظل هو العقدة الجذر لشجرة الظل.

تختار الفئة الزائفة :host العنصر <star-rating>، وهو عنصر مضيف الظل. مضيف الظل هو عقدة DOM التي يتم ربط shadow DOM بها. ولاستهداف إصدارات معيّنة فقط من المضيف، استخدِم :host(). سيؤدي هذا إلى اختيار عناصر مضيف الظل التي تطابق المعلمة التي تم تمريرها فقط، مثل الفئة أو محدد السمة. لتحديد جميع العناصر المخصصة، يمكنك استخدام star-rating { /* styles */ } في CSS العام، أو :host(:not(#nonExistantId)) في أنماط النماذج. من حيث للخصوصية، هي التي تفوز بها خدمة CSS العالمية.

يتخطى العنصر الزائف ::slotted() حدود shadow DOM من داخل shadow DOM. ويختار عنصرًا بخانة إذا تطابق مع المحدِّد. في المثال الذي ذكرناه، تتطابق ::slotted(legend) مع وسائل الإيضاح الثلاث.

لاستهداف shadow DOM من CSS في النطاق العمومي، يجب تعديل النموذج. part إلى أي عنصر تريد تصميمه. بعد ذلك، استخدِم العنصر الزائف ::part(). لمطابقة العناصر في شجرة ظل تطابق المعلمة التي تم تمريرها. يعتبر ارتساء العنصر الزائف أو العنصر المنشأ المضيف أو اسم العنصر المخصص، وهو في هذه الحالة star-rating. المَعلمة هي قيمة سمة part.

إذا بدأ ترميز النموذج كما يلي:

<template id="star-rating-template">
  <form part="formPart">
    <fieldset part="fieldsetPart">

يمكننا استهداف <form> و<fieldset> من خلال:

star-rating::part(formPart) { /* styles */ }
star-rating::part(fieldsetPart) { /* styles */ }

تعمل أسماء الأجزاء بشكل مشابه للفئات: يمكن أن يحتوي العنصر على أسماء متعددة مفصولة بمسافة، ويمكن للعناصر المتعددة أن لها نفس اسم الجزء.

لدى Google قائمة تحقق رائعة لإنشاء عناصر مخصصة. قد ترغب أيضًا في معرفة حول نماذج shadow DOM التعريفية.

التحقق من فهمك

اختبر معلوماتك عن القالب والخانة والظل.

وبشكلٍ تلقائي، ستحدّد الأنماط من خارج shadow DOM العناصر بالداخل.

صحيح
يُرجى إعادة المحاولة.
خطأ
إجابة صحيحة.

ما هي الإجابة التي تصف الوصف الصحيح لعنصر <template>؟

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