Shadow DOM، الگوها، و شکاف‌ها

ویژگی‌های وب: Shadow DOM <slot>

ریشه سایه یک زیردرخت DOM کپسوله‌شده است که به عنصر میزبان متصل شده است: سبک‌های داخل آن به بیرون نشت نمی‌کنند و سبک‌های صفحه به داخل نشت نمی‌کنند (به‌جز ویژگی‌های موروثی). الگوها درخت را به‌طور کارآمد می‌سازند؛ جایگاه‌ها محتوای Light DOM را در آن نمایش می‌دهند.

درحال پیوست کردن ریشه سایه

this.attachShadow({ mode: 'open', delegatesFocus: true });

delegatesFocus: true باعث می‌شود تمرکز روی میزبان، تمرکز را به اولین عنصر قابل‌تمرکز در درخت سایه منتقل کند، سبک‌بندی :focus را به میزبان هدایت می‌کند، و در عناصر سفارشی مرتبط با فرم (static formAssociated = true)، کلیک‌های <label> را به کنترل داخلی بازارسال می‌کند. هرگاه مؤلفه کنترل‌های قابل‌تمرکز را دربرمی‌گیرد، آن را تنظیم کنید. تقریباً در همه موارد از mode: 'open' استفاده کنید تا ابزارهای توسعه، اسکریپت‌های صفحه، و هیدراتاسیون سرور بتوانند به element.shadowRoot دسترسی پیدا کنند (به جهت‌گیری مؤلفه‌های وب مراجعه کنید).

الگوها: ساختن درخت به‌صورت کارآمد

<template> را یک‌بار (محدوده ماژول یا فیلد ایستا) تعریف کنید و آن را برای هر نمونه کلون کنید. کلون کردن قطعه تجزیه‌شده بسیار سریع‌تر از تجزیه مجدد رشته innerHTML در هر ساخت است.

const template = document.createElement('template');
template.innerHTML = `
  <div class="card">
    <slot name="header"></slot>
    <div class="body"><slot></slot></div>
    <slot name="footer"></slot>
  </div>
`;

class MyCard extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    // MANDATORY: deep-clone the template content so each instance gets its own nodes.
    this.shadowRoot.append(template.content.cloneNode(true));
  }
}
customElements.define('my-card', MyCard);

الگوها را ساده نگه دارید. ‫«div soup» تودرتوی عمیق و سطوح متعدد ریشه‌های سایه تودرتو، هر دو هزینه قابل‌اندازه‌گیری برای وضوح سبک و چیدمان اضافه می‌کنند که تأثیر عمده‌ای بر عملکرد در مقیاس بزرگ دارد. ساختار مسطح و عناصر معنایی را ترجیح دهید.

شکاف‌ها: بخش‌هایی که افراد را غافلگیر می‌کند

شکاف‌های پیش‌فرض درمقابل شکاف‌های نام‌گذاری‌شده طبق مستندات کار می‌کنند؛ این‌ها رفتارهایی هستند که مشکل‌ساز می‌شوند:

  • فاصله سفید مهم است. گره‌های نوشتار بین عناصر (ازجمله فضای خالی خالص) به شکاف پیش‌فرض اختصاص داده می‌شوند، بنابراین شکاف پیش‌فرض به‌ندرت واقعاً «خالی» است.
  • ترتیب DOM حفظ می‌شود، نه ترتیب جایگاه. گره‌های پیش‌بینی‌شده ترتیب Light DOM اصلی خود را برای اهداف :first-child/:last-child حفظ می‌کنند، صرف‌نظر از اینکه کدام شکاف را پر می‌کنند. قانون ::slotted(*:first-child) اولین فرزند DOM را هدف قرار می‌دهد، نه اولین فرزند آن جایگاه، بنابراین اغلب با آنچه انتظار دارید مطابقت نخواهد داشت.
  • slotchange سیگنال زمان ارتقا است. این رویداد زمانی فعال می‌شود که گره‌های اختصاص‌داده‌شده تغییر کنند (ازجمله اختصاص اولیه) و روشی مطمئن برای اطلاع از رسیدن فرزندان Light DOM پس‌از ارتقا است، زمانی که ممکن است درطول connectedCallback وجود نداشته باشند.
this.shadowRoot.querySelector('slot[name="header"]')
  .addEventListener('slotchange', (e) => {
    const nodes = e.target.assignedElements();
    this.toggleAttribute('has-header', nodes.length > 0);
  });

درحال بار کردن برگه‌های سبک نگارش در ریشه سایه

روش مزایا معایب
<style> در الگو ساده، کاملاً کپسوله‌شده، بدون JS کار می‌کند. برای هر نمونه تکرار می‌شود؛ DOM را در مقیاس بزرگ متورم می‌کند.
<link rel="stylesheet"> فایل خارجی قابل‌ذخیره در حافظه نهان. درخواست اضافی؛ خطر چشمک زدن محتوای بدون سبک.
adoptedStyleSheets یک CSSStyleSheet مشترک در همه نمونه‌ها؛ سریع‌ترین در مقیاس. به JS نیاز دارد؛ برگ‌های ساخته‌شده از @import پشتیبانی نمی‌کنند.

برای نمونه‌های متعدد از یک مؤلفه، برگه سبک نگارش ساخته‌شده مشترک را ترجیح دهید:

const sheet = new CSSStyleSheet();
sheet.replaceSync(`:host { display: block; }`);

class MyCard extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    // The same sheet object is reused by every instance; no per-instance parse.
    this.shadowRoot.adoptedStyleSheets = [sheet];
  }
}