Shadow DOM في TypeScript

Shadow DOM في TypeScript

توضح هذه المقالة Shadow DOM في TypeScript۔

سنشرح بعناية كل شيء من أساسيات Shadow DOM إلى استخداماته العملية، وسنوفر أمثلة برمجية تطبيقية.۔

YouTube Video

typescript-html-shadow-dom.html
  1<!DOCTYPE html>
  2<html lang="en">
  3<head>
  4  <meta charset="UTF-8">
  5  <title>TypeScript &amp; HTML</title>
  6  <style>
  7    * {
  8        box-sizing: border-box;
  9    }
 10
 11    body {
 12        margin: 0;
 13        padding: 1em;
 14        padding-bottom: 10em;
 15        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 16        background-color: #f7f9fc;
 17        color: #333;
 18        line-height: 1.6;
 19    }
 20
 21    .container {
 22        max-width: 800px;
 23        margin: 0 auto;
 24        padding: 1em;
 25        background-color: #ffffff;
 26        border: 1px solid #ccc;
 27        border-radius: 10px;
 28        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 29    }
 30
 31    h1, h2 {
 32        font-size: 1.2rem;
 33        color: #007bff;
 34        margin-top: 0.5em;
 35        margin-bottom: 0.5em;
 36        border-left: 5px solid #007bff;
 37        padding-left: 0.6em;
 38        background-color: #e9f2ff;
 39    }
 40
 41    button {
 42        display: block;
 43        margin: 1em auto;
 44        padding: 0.75em 1.5em;
 45        font-size: 1rem;
 46        background-color: #007bff;
 47        color: white;
 48        border: none;
 49        border-radius: 6px;
 50        cursor: pointer;
 51        transition: background-color 0.3s ease;
 52    }
 53
 54    button:hover {
 55        background-color: #0056b3;
 56    }
 57
 58    #output {
 59        margin-top: 1em;
 60        background-color: #1e1e1e;
 61        color: #0f0;
 62        padding: 1em;
 63        border-radius: 8px;
 64        min-height: 200px;
 65        font-family: Consolas, monospace;
 66        font-size: 0.95rem;
 67        overflow-y: auto;
 68        white-space: pre-wrap;
 69    }
 70
 71    .highlight {
 72        outline: 3px solid #ffc107; /* yellow border */
 73        background-color: #fff8e1;  /* soft yellow background */
 74        transition: background-color 0.3s ease, outline 0.3s ease;
 75    }
 76
 77    .active {
 78        background-color: #28a745; /* green background */
 79        color: #fff;
 80        box-shadow: 0 0 10px rgba(40, 167, 69, 0.5);
 81        transition: background-color 0.3s ease, box-shadow 0.3s ease;
 82    }
 83  </style>
 84</head>
 85<body>
 86    <div class="container">
 87        <h2>HTML Sample</h2>
 88        <div id="content"></div>
 89    </div>
 90
 91    <div class="container">
 92        <h1>JavaScript Console</h1>
 93        <button id="executeBtn">Execute</button>
 94        <div id="output"></div>
 95    </div>
 96
 97    <script>
 98        // Override console.log to display messages in the #output element
 99        (function () {
100            const originalLog = console.log;
101            console.log = function (...args) {
102                originalLog.apply(console, args);
103                const output = document.getElementById('output');
104                output.textContent += args.map(String).join(' ') + '\n';
105            };
106        })();
107
108        document.getElementById('executeBtn').addEventListener('click', () => {
109            // Prevent multiple loads
110            if (document.getElementById('externalScript')) return;
111
112            const script = document.createElement('script');
113            script.src = '/out/main.js';
114            script.id = 'externalScript';
115            //script.onload = () => console.log('typescript-html-shadow-dom.js loaded and executed.');
116            //script.onerror = () => console.log('Failed to load typescript-html-shadow-dom.js.');
117            document.body.appendChild(script);
118        });
119    </script>
120</body>
121</html>

شرح تفصيلي ودليل عملي خطوة بخطوة حول Shadow DOM

يُعتبر Shadow DOM أحد المكونات الرئيسية لمكونات الويب. يقوم بإنشاء شجرة DOM مغلقة تفصل بين أسلوب وهيكل المكون والعناصر الخارجية.۔ هنا، سنقدم شرحًا مفصلًا لأساسيات Shadow DOM وصولًا إلى حالاته العملية، مع أمثلة واقعية على الكود.۔

ما هو Shadow DOM؟

تقنية Shadow DOM هي معيار ويب تتمتع بالخصائص التالية۔

  1. التغليف (Encapsulation)

    Shadow DOM يفصل بين البنية الداخلية للـ DOM الخاصة بالمكون وبين العناصر الخارجية۔ لا تتداخل الأنماط والبرمجيات الخارجية، مما يعزز إمكانية إعادة الاستخدام۔

  2. نطاق أنماط مستقل

    الأنماط داخل Shadow DOM لا تؤثر على الـ CSS الخارجي۔ وبالمثل، الأنماط الخارجية لا تُستخدم داخل Shadow DOM۔

  3. شجرة DOM معزولة

    Shadow DOM يوجد كجزء منفصل عن شجرة DOM العادية، مع قيود على الوصول إليه من DOM الرئيسي۔

الاستخدام الأساسي لـ Shadow DOM

الكود التالي هو المثال الأول لاستخدام Shadow DOM۔

 1class MyElement extends HTMLElement {
 2  constructor() {
 3    super();
 4
 5    // Attach Shadow DOM
 6    const shadowRoot = this.attachShadow({ mode: 'open' });
 7
 8    // Add HTML and CSS inside Shadow DOM
 9    shadowRoot.innerHTML = `
10      <style>
11        p {
12          color: blue;
13          font-size: 18px;
14        }
15      </style>
16      <p>This is inside Shadow DOM!</p>
17    `;
18  }
19}
20
21// Register the custom element
22customElements.define('my-element', MyElement);
23
24document.getElementById('content').innerHTML = `
25  <my-element></my-element>
26`;
  • سيعرض المتصفح النص الأزرق: 'هذا داخل Shadow DOM!'۔ لا يتأثر نمط هذا النص بـ CSS الخارجية۔

الخطوات الأساسية لـ Shadow DOM

لاستخدام Shadow DOM، كما هو موضح في هذا الكود، تستخدم طريقة attachShadow في جافاسكريبت.۔ فيما يلي الخطوات الأساسية:۔

  1. إنشاء عناصر مخصصة (Custom Elements) العنصر المخصص هو وسم معرف من قبل المستخدم يمكنك إنشاؤه بالإضافة إلى الوسوم القياسية في HTML.۔ في هذه الخطوة، تنشئ فئة (class) ترث من HTMLElement، مثل فئة MyElement، لإعداد المتصفح للتعرف عليها كوسم جديد.۔ من خلال تسجيل الفئة التي أنشأتها باستخدام customElements.define()، يمكنك استخدامها كوسم مخصص داخل HTML.۔

  2. إرفاق Shadow DOM عند تنفيذ this.attachShadow() داخل عنصر مخصص، يمكنك إنشاء Shadow DOM

  3. إضافة HTML و CSS داخل Shadow DOM داخل Shadow DOM يمكنك تحديد البنية (structure) والأنماط (styles) الخاصة بك.۔ على سبيل المثال، من خلال تعيين HTML وCSS إلى innerHTML، يمكنك منحه مظهرًا وسلوكًا مستقلين دون التأثر بـ CSS أو HTML الخارجي.۔ يسمح لك ذلك بإنشاء مكونات (components) مغلّفة.۔

وضعيات Shadow DOM: مفتوح ومغلق

يحتوي Shadow DOM على وضعين: مفتوح ومغلق۔

  • الوضع المفتوح: يمكن الوصول إلى shadowRoot المرتبط بـ Shadow DOM من الخارج۔
  • الوضع المغلق: لا يمكن الوصول إلى shadowRoot المرتبط بـ Shadow DOM من الخارج۔

فيما يلي مثال على كود يوضح الفروقات بين الوضعين۔

 1class OpenElement extends HTMLElement {
 2  constructor() {
 3    super();
 4    this.attachShadow({ mode: 'open' }).innerHTML = `
 5      <p>Open Shadow DOM</p>
 6    `;
 7  }
 8}
 9
10class ClosedElement extends HTMLElement {
11  constructor() {
12    super();
13    this.attachShadow({ mode: 'closed' }).innerHTML = `
14      <p>Closed Shadow DOM</p>
15    `;
16  }
17}
18
19customElements.define('open-element', OpenElement);
20customElements.define('closed-element', ClosedElement);
21
22document.getElementById('content').innerHTML = `
23  <open-element></open-element>
24  <closed-element></closed-element>
25`;
26
27const openElement = document.querySelector('open-element') as OpenElement;
28console.log(openElement.shadowRoot); // ShadowRootが出力される
29
30const closedElement = document.querySelector('closed-element') as ClosedElement;
31console.log(closedElement.shadowRoot); // nullが出力される
  • اختيار الوضع المغلق يجعل خاصية shadowRoot غير قابلة للوصول۔

احتواء الأنماط باستخدام Shadow DOM

باستخدام Shadow DOM، يمكنك احتواء الأنماط بالكامل داخل مكوناتك۔

يُظهر المثال التالي فصل الأنماط العالمية عن الأنماط داخل Shadow DOM۔

 1class StyledElement extends HTMLElement {
 2  constructor() {
 3    super();
 4    const shadowRoot = this.attachShadow({ mode: 'open' });
 5
 6    shadowRoot.innerHTML = `
 7      <style>
 8        p {
 9          background-color: lightblue;
10          padding: 10px;
11          border: 1px solid blue;
12        }
13      </style>
14      <p>Shadow DOM Styled Content</p>
15    `;
16  }
17}
18
19customElements.define('styled-element', StyledElement);
20
21document.getElementById('content').innerHTML = `
22  <style>
23    p {
24      color: red;
25      font-weight: bold;
26    }
27  </style>
28
29  <styled-element></styled-element>
30`;
  • العناصر p داخل الـ Shadow DOM لا تتأثر بالأنماط العامة ويتم تطبيق أنماط فريدة خاصة بها۔

مثال عملي على Shadow DOM: أداة تلميحات مخصصة

بعد ذلك، نقدم مثالاً لإنشاء أداة تلميحات مخصصة باستخدام Shadow DOM۔

 1class Tooltip extends HTMLElement {
 2  constructor() {
 3    super();
 4
 5    const shadowRoot = this.attachShadow({ mode: 'open' });
 6
 7    shadowRoot.innerHTML = `
 8      <style>
 9        :host {
10          position: relative;
11          display: inline-block;
12          cursor: pointer;
13        }
14
15        .tooltip {
16          visibility: hidden;
17          background-color: black;
18          color: white;
19          text-align: center;
20          padding: 5px;
21          border-radius: 5px;
22          position: absolute;
23          bottom: 125%;
24          left: 50%;
25          transform: translateX(-50%);
26          white-space: nowrap;
27        }
28
29        :host(:hover) .tooltip {
30          visibility: visible;
31        }
32      </style>
33      <slot></slot>
34      <div class="tooltip">Tooltip text</div>
35    `;
36  }
37}
38
39customElements.define('custom-tooltip', Tooltip);
40
41document.getElementById('content').innerHTML = `
42  <custom-tooltip>
43    Hover over me
44    <span slot="tooltip">This is a custom tooltip!</span>
45  </custom-tooltip>
46`;
  • تنشئ هذه الشفرة أداة تلميحات مخصصة وتعرض أداة تلميحات منسقة عند التمرير۔

الملخص

Shadow DOM هي تقنية أساسية لمكونات الويب، حيث توفر DOM مغلف ونطاقًا للأنماط۔ هنا، تناولنا أساسيات Shadow DOM، واستخدامه، واختلاف الوضعيات، واحتواء الأنماط، والأمثلة العملية۔ من خلال الاستفادة من هذه الميزات، يمكنك بناء مكونات قابلة لإعادة الاستخدام وقوية.۔

يمكنك متابعة المقالة أعلاه باستخدام Visual Studio Code على قناتنا على YouTube.۔ يرجى التحقق من القناة على YouTube أيضًا.۔

YouTube Video