يعني العرض المُسبق إرسال ترميز عنصر مخصّص، بما في ذلك شجرة الظل، من الخادم، بحيث يتم تصميم المكوّن وتنظيمه قبل تشغيل أي رمز JavaScript. العنصر الأساسي الرئيسي في المنصة لهذا الغرض هو Declarative Shadow DOM (DSD): يربط المحلل اللغوي جذر الظل من HTML فقط، وتتم ترقية العنصر لاحقًا ("تنشيطه") من خلال فئته إذا تم تسجيله. استخدِم هذا النمط للعرض على جهة الخادم، والبث، وتجنُّب وميض المحتوى غير المنسَّق (FOUC).
إنشاء جذر ظل تعريفي
أدرِج علامة <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 لإجراء عملية التنشيط. لإجراء تسلسل لـ shadow root حالي وإعادته إلى HTML على الخادم أو في الاختبارات، استخدِم getHTML({ serializableShadowRoots: true }) وأرفِق الجذر باستخدام serializable: true.
تجنُّب وميض المحتوى غير المنسَّق (FOUC)
يتم عرض DSD بشكل صحيح في أول عرض فقط إذا تم إرسال الأنماط داخل النموذج التعريفي. للحفاظ على ذلك:
- ضَع CSS الخاص بالمكوّن داخل
<template shadowrootmode>(علامة<style>أو<link>)، وليس في ورقة منفصلة يتم تحميلها باستخدام نص برمجي. - استخدِم
my-card:not(:defined) { … }فقط مع الأنماط التي يجب أن تنتظر JS، مثل قواعد الحماية على مستوى الصفحة، مثل التلاشي في النُسخ المعروضة من جهة العميل والتي لا تتضمّن عرضًا من جهة الخادم. وتكون هذه العناصر في ورقة أنماط light-DOM (الصفحة)، لأنّ جذر الظل غير متوفّر بعد هناك ولا تنطبق أدوات الاختيار:hostمن الخارج. ولا تحتاج الأنماط الهيكلية داخل نموذج DSD إلى مثل هذا الإجراء. - Do not re-render the shadow tree on hydration. يتم التعامل مع ترميز الخادم على أنّه موثوق ويتم إرفاق السلوك به.
استراتيجيات احتياطية
في المحركات التي لا تحلل shadowrootmode، يكون النموذج خاملًا ولا يتم إرفاق محتواه كجذر ظل. يمكنك رصد هذا (Object.hasOwn(HTMLTemplateElement.prototype, 'shadowRootMode'))، وإذا لم يكن موجودًا، يمكنك إرفاق جذر الظل بشكل حتمي من الترميز نفسه أثناء الترقية حتى يستمر عرض المكوّن.