۳۱ ژانویه ۲۰۲۴

Shadow DOM

دلیل استفاده از shadow DOM جداسازی یا کپسوله کردن است. shadow DOM به یک المنت اجازه می دهد تا سند DOM نهان(shadow) خود را داشته باشد، که به طور کامل از DOM سند اصلی جداسازی شده است، سند shadow DOM می‌تواند قوانین خاص خود را داشته باشد مثل style محلی مربوط به خود.

Shadow DOM های داخلی (Built-in)

آیا تا به حال فکر کرده‌اید که چگونه کنترلرهای پیچیده مرورگر مثل المان زیر (ورودی محدود) ایجاد شده و style دهی می‌شوند؟

<input type="range">:

مرورگر با DOM/CSS آن‌ها را پیاده سازی می‌کند. ساختار DOM این المان‌ها از دیدگاه ما پنهان است ولی با استفاده از developer tools می‌توان به آن‌ها دسترسی پیدا کرد٬ برای مثال در chrome کافی‌ است گزینه “Show user agent shadow DOM” را در Dev tools فعال کنید.

برای مثال <"input type="range> به شکل زیر است.

همه اجزای زیرمجموعه‌ی shadow-root# را می‌توان “shadow DOM” نامید.

چون المان‌های Shadow DOM داخلی (built-in) از المان‌های معمول DOM جدا سازی شده‌اند نمی‌توان با استفاده از انتخابگرهای معمول جاوااسکریپت مرورگر به آنها دسترسی پیدا کرد.

اگر در مثال بالا توجه کنید یک attribute به نام pseudo می‌بینید.pseudo یک ویژگی غیر استاندارد است که وجود آن دلایل تاریخی دارد اما با استفاده از آن می‌توانیم المان‌های زیرمجموعه را به شکل زیر style دهی کنیم.

<style>
/* رنگ ریل را به قرمز تغییر می‌دهد */
input::-webkit-slider-runnable-track {
  background: red;
}
</style>

<input type="range" />

فراموش نکنید که pseudo یک ویژگی غیر استاندارد است. مرورگر‌ها در ابتدا به پیاده‌سازی آزمایشی کنترل‌های داخلی با استفاده از المان‌های DOM کردند بعد از گذشت زمان shadow DOM استاندارد سازی شد تا توسعه دهندگان بتوانند المان‌های کنترلی خود را بسازند.

در ادامه از shadow DOM استاندارد استفاده خواهیم کرد که در DOM spec توضیحات کاملی از آن موجود است.

درخت سایه (Shadow Tree)

یک المان DOM می‌تواند دو نوع زیرمجموعه DOM داشته باشد:

  1. light tree – یک زیر مجموعه معمولی از DOM است که از زیرمجموعه HTML ساخته شده است. تمام مثال‌های که در فصول قبل دیدیم از نوع light بودند.
  2. shadow tree – یک زیرمجموعه پنهان از DOM است که در HTML نمایش داده نمی‌شود و از چشم مخفی است.

اگر المانی هر دو زیرمجموعه را داشت مرورگر فقط قسمت shadow را نمایش خواهد داد. اما می توانیم نوعی ترکیب بندی بین shadow treeها و light ایجاد کنیم. جزیات بیشتر را در Shadow DOM slots, composition خواهیم خواند.

می‌توان از shadow tree برای پنهان سازی المان‌های داخلی استفاده کرد و از استایل دهی محلی برای المان جدید استفاده کرد.

برای مثال<show-hello> المان‌های داخلی خود را در shadow tree پنهان می‌کند و مقدار نمایش داده شده را به عنوان ویژگی دریافت می‌کند.

<script>
customElements.define('show-hello', class extends HTMLElement {
  connectedCallback() {
    const shadow = this.attachShadow({mode: 'open'});
    shadow.innerHTML = `<p>
      Hello, ${this.getAttribute('name')}
    </p>`;
  }
});
</script>

<show-hello name="John"></show-hello>

خروجی DOM بالا در Chrome dev tool به شکل زیر نشان داده می‌شود و تمام اجزا زیر مجموعه “shadow-root#” خواهد بود.

در ابتدا elem.attachShadow({mode: …}) یک shadow tree ایجاد می‌کند.

ما در این جا ۲ محدودیت داریم:

  1. هر المان در صفحه فقط می‌تواند یک shadow داشته باشد.
  2. المان elem باید یک المان سفارشی سازی شده(custom) یا یکی از المان های “article”, “aside”, “blockquote”, “body”, “div”, “footer”, “h1…h6”, “header”, “main” “nav”, “p”, “section”, “span” باشد. دیگر المان ها مثل <img> نمی‌توانند shadow داشته باشند.