پیش‌پرداز زدن عناصر سفارشی

ویژگی‌های وب: DOM سایه اعلانی

پیش‌پرداخت به‌معنای ارسال نشانه‌گذاری عنصر سفارشی — ازجمله درخت سایه آن — از سرور است، بنابراین مؤلفه قبل‌از اجرای هرگونه جاوا اسکریپت سبک‌بندی و ساختاردهی می‌شود. پایه اصلی پلاتفرم برای این کار Declarative Shadow DOM (DSD) است: تجزیه‌کننده ریشه سایه را فقط از HTML پیوست می‌کند، و عنصر بعداً توسط کلاس خود (درصورت ثبت شدن) ارتقا می‌یابد («هیدراته می‌شود»). از این الگو برای پردازش سمت سرور، جاری‌سازی، و اجتناب از فلش محتوای بدون سبک (FOUC) استفاده کنید.

Authoring a declarative shadow root

یک <template> را با مشخصه shadowrootmode به‌عنوان اولین فرزند میزبان آشیانه کنید. تجزیه‌کننده محتوای آن را به‌عنوان ریشه سایه پیوست می‌کند و الگو را برمی‌دارد؛ به هیچ اسکریپتی نیاز نیست.

<my-card>
  <template shadowrootmode="open">
    <style>
      .card { border: 1px solid; border-radius: 8px; padding: 1rem; }
    </style>
    <div class="card">
      <slot name="header"></slot>
      <div class="body"><slot></slot></div>
    </div>
  </template>

  <!-- Light DOM children are projected into the slots above. -->
  <h2 slot="header">Server-rendered title</h2>
  <p>Visible and styled before JS loads.</p>
</my-card>

زمان‌بندی آب‌رسانی

وقتی کلاس منطبق ثبت شود، مرورگر میزبان را ارتقا می‌دهد. چون ریشه سایه ازقبل وجود دارد، سازنده نباید بدون بررسی ریشه دوم را ایجاد کند:

class MyCard extends HTMLElement {
  constructor() {
    super();
    // Reuse the server-rendered shadow root if present; only create one if absent.
    if (!this.shadowRoot) {
      this.attachShadow({ mode: 'open' });
      this.shadowRoot.append(template.content.cloneNode(true));
    }
    // Hydrate in place: attach listeners once against existing markup (not unguarded
    // in connectedCallback, which re-runs if the element moves in the DOM), and do
    // NOT re-render; that would discard the server's DOM and flash.
    this.shadowRoot.getElementById('toggle')
      ?.addEventListener('click', () => this.toggleAttribute('open'));
  }
}

برای تقریباً همه موارد، shadowrootmode="open" (نه closed) را تنظیم کنید تا اسکریپت‌ها و ابزارها بتوانند برای هیدراته کردن به this.shadowRoot دسترسی پیدا کنند. برای سریال‌سازی ریشه سایه موجود به HTML در سرور یا در آزمایش‌ها، از getHTML({ serializableShadowRoots: true }) استفاده کنید و ریشه را با serializable: true پیوست کنید.

پرهیز از FOUC

DSD فقط درصورتی در اولین رنگ‌آمیزی به‌درستی ارائه می‌شود که سبک‌ها در داخل الگوِ اعلانی ارسال شوند. برای حفظ آن:

  • سرویس مقایسه قیمت مؤلفه را داخل <template shadowrootmode> (برچسب <style> یا <link>) قرار دهید، نه در برگه بارشده دستورگان جداگانه.
  • فقط برای سبک‌هایی که باید منتظر جاوااسکریپت بمانند، با my-card:not(:defined) { … } جفت کنید — معمولاً قوانین محافظ سطح صفحه مانند محو شدن در نمونه‌های ارائه‌شده توسط کارخواه که گذر SSR را ازدست می‌دهند. این‌ها در برگه سبک نگارش light-DOM (صفحه) قرار دارند، زیرا ریشه سایه هنوز در آنجا وجود ندارد و انتخاب‌کننده‌های :host از بیرون اعمال نمی‌شوند. سبک‌های ساختاری داخل الگوی DSD به چنین محافظی نیاز ندارند.
  • Do not re-render the shadow tree on hydration. نشانه‌گذاری سرور را به‌عنوان معتبر درنظر بگیرید و رفتار را به آن پیوست کنید.

راهبردهای جایگزین

در موتورهایی که shadowrootmode را تجزیه نمی‌کنند، الگو بی‌اثر است و محتوای آن به‌عنوان ریشه سایه پیوست نمی‌شود. این (Object.hasOwn(HTMLTemplateElement.prototype, 'shadowRootMode')) را شناسایی کنید و اگر وجود نداشت، ریشه سایه را به‌طور الزامی از همان نشانه‌گذاری درطول ارتقا پیوست کنید تا مؤلفه همچنان ارائه شود.