سجلدوم في جافا سكريبت
توضح هذه المقالة سجلدوم في جافا سكريبت۔
YouTube Video
javascript-html-shadow-dom.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>JavaScript & 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 id="shadow-host">Shadow Root Element</div>
90 <my-card></my-card>
91 </div>
92
93 <div class="container">
94 <h1>JavaScript Console</h1>
95 <button id="executeBtn">Execute</button>
96 <div id="output"></div>
97 </div>
98
99 <div>
100 <h2>Slot Sample</h2>
101 <my-element>
102 <h3 slot="header">Header Content</h1>
103 <p slot="content">Main Content</p>
104 </my-element>
105 </div>
106
107 <script>
108 // Override console.log to display messages in the #output element
109 (function () {
110 const originalLog = console.log;
111 console.log = function (...args) {
112 originalLog.apply(console, args);
113 const output = document.getElementById('output');
114 output.textContent += args.map(String).join(' ') + '\n';
115 };
116 })();
117
118 document.getElementById('executeBtn').addEventListener('click', () => {
119 // Prevent multiple loads
120 if (document.getElementById('externalScript')) return;
121
122 const script = document.createElement('script');
123 script.src = 'javascript-html-shadow-dom.js';
124 script.id = 'externalScript';
125 //script.onload = () => console.log('javascript-html-shadow-dom.js loaded and executed.');
126 //script.onerror = () => console.log('Failed to load javascript-html-shadow-dom.js.');
127 document.body.appendChild(script);
128 });
129 </script>
130</body>
131</html>
فهم Shadow DOM
Shadow DOM
هي ميزة قوية في معيار Web Components تتيح تغليف الأنماط وبنية DOM داخل المكونات۔ تمنع هذه الميزة تداخل الأنماط والسكربتات بين المكونات والمستند الرئيسي۔
Shadow DOM
في جافا سكريبت
Shadow DOM
يوفر طريقة لإنشاء شجرة DOM محدودة ترتبط بعنصر DOM عادي۔ تكون هذه الشجرة الظلية معزولة عن المستند الكلي، حيث لا تؤثر عليها الأنماط والسكربتات الخارجية، ولا تتسرب الأنماط والسكربتات الداخلية منها۔
على سبيل المثال، إذا قمت بإنشاء مكون زر مخصص باستخدام Shadow DOM
، فإن أنماطه لن تتداخل مع العناصر الأخرى على الصفحة۔ وبالمثل، لن تتعارض العناصر التي تحمل نفس اسم الفئة۔
يشار إلى محتوى HTML العادي خارج Shadow DOM
باسم Light DOM
۔
فوائد Shadow DOM
-
الكبسلة (Encapsulation)
Shadow DOM
يفصل بين التنسيق (الأنماط) والوظائف، مما يمنع التعارض مع الأنماط والنصوص البرمجية العامة۔
-
إعادة الاستخدام
- يمكن إعادة استخدام المكونات المبنية باستخدام
Shadow DOM
في مشاريع مختلفة بدون القلق من تعارض الأنماط۔
- يمكن إعادة استخدام المكونات المبنية باستخدام
-
سهولة الصيانة
- تجعل الكبسلة (Encapsulation) من منطق المكون وتنسيقه مستقلين، مما يسهل التصحيح والصيانة۔
إنشاء Shadow DOM
لاستخدام Shadow DOM
، تحتاج إلى إرفاق جذر الظل بعنصر HTML۔ إليك مثال بسيط:۔
1// Select the host element
2const hostElement = document.querySelector('#shadow-host');
3
4// Attach a shadow root
5const shadowRoot = hostElement.attachShadow({ mode: 'open' });
الشرح
يتضمن هذا الكود العناصر التالية:۔
-
عنصر الاستضافة (Host Element)
- عنصر DOM عادي يتم إرفاق جذر الظل (shadow root) به (في هذه الحالة،
#shadow-host
)۔
- عنصر DOM عادي يتم إرفاق جذر الظل (shadow root) به (في هذه الحالة،
-
جذر الظل (Shadow Root)
- هو جذر شجرة الظل التي تم إنشاؤها باستخدام
attachShadow
۔
- هو جذر شجرة الظل التي تم إنشاؤها باستخدام
-
الوضع (Mode)
- في وضع
open
، يمكن لجافاسكريبت الخارجي الوصول إلى جذر الظل عبرelement.shadowRoot
۔ من ناحية أخرى، لا يسمح الوضعclosed
بالوصول۔
- في وضع
التنسيق داخل Shadow DOM
لـ Shadow DOM
نطاق أنماطه الخاص۔ الأنماط المحددة داخل شجرة الشادو تنطبق فقط على العناصر داخل تلك الشجرة۔ إليك مثالاً:۔
1// Add content to the shadow root
2shadowRoot.innerHTML = `
3 <style>
4 p {
5 color: green;
6 }
7 </style>
8 <p>Scoped style inside Shadow DOM.</p>
9`;
حتى لو كانت هناك أنماط متعارضة في المستند الرئيسي، فإنها لا تؤثر على الفقرة داخل شجرة الظل۔
1const content = document.getElementById('content');
2content.innerHTML = `
3 <style>
4 p {
5 color: red;
6 }
7 </style>
8 <p>This is in the main DOM.</p>
9`;
- تظل الفقرة داخل
Shadow DOM
خضراء، بينما تكون الفقرة الخارجية حمراء۔
الأحداث داخل Shadow DOM
الأحداث داخل Shadow DOM
تشبه الأحداث العادية في DOM ولكنها قد تتصرف بشكل مختلف من حيث الانتشار بسبب التغليف۔
إليك مثالاً:۔
1// Add an event listener inside Shadow DOM
2shadowRoot.innerHTML = `
3 <div id="button-container">
4 <button id="shadow-button">Click Me</button>
5 </div>
6`;
7
8shadowRoot.querySelector('#shadow-button').addEventListener('click', (event) => {
9 console.log('Button : Button clicked inside Shadow DOM');
10 console.log(event.target);
11});
12
13shadowRoot.querySelector('#button-container').addEventListener('click', (event) => {
14 console.log('Container : Button clicked inside Shadow DOM');
15 console.log(event.target);
16});
17
18hostElement.addEventListener('click', (event) => {
19 console.log('Event bubbled to the host element');
20 console.log(event.target);
21});
22
23document.addEventListener('click', (event) => {
24 console.log('Document listener');
25 console.log(event.target);
26});
- عند النقر على الزر، يتم تشغيل كلا المستمعين، مما يظهر سلوك انتقال الأحداث۔
- عندما ينتقل حدث نشأ داخل
Shadow DOM
إلىLight DOM
, يتم إعادة كتابة خاصيةtarget
للحدث إلى عنصر المستضيف بدلاً من المصدر الأصلي۔- في هذا المثال، تكون
event.target
داخلShadow DOM
هي عنصرbutton
الفعلي، ولكن خارجShadow DOM
يتم استبدالها بعنصر المستضيفdiv
۔
- في هذا المثال، تكون
Shadow DOM
والعناصر المخصصة
Shadow DOM
والعناصر المخصصة هما من المكونات الرئيسية لـ Web Components
۔ هي تقنيات تُستخدم لإنشاء مكونات واجهة مستخدم قابلة لإعادة الاستخدام ومعزولة۔
1class MyCard extends HTMLElement {
2 constructor() {
3 super();
4 const shadow = this.attachShadow({ mode: 'open' });
5 shadow.innerHTML = `
6 <style>
7 p {
8 color: blue;
9 }
10 </style>
11 <p>I'm inside shadow DOM</p>
12 `;
13 }
14}
15
16customElements.define('my-card', MyCard);
يحتوي المستند الرئيسي على HTML بهذا الشكل:۔
1<my-card></my-card>
- من خلال استخدام
Shadow DOM
داخل العناصر المخصصة، يمكنك بناء مكونات قابلة لإعادة الاستخدام ومقاومة لتعارض الأنماط۔ في هذا الكود، يتم إنشاء وسم باسمmy-card
ويرتبط بفئةMyCard
۔ عنصر<p>
داخلmy-card
لا يتأثر بالأنماط الخارجية ويظهر دائماً باللون الأزرق۔
الفتحات (Slots): توزيع محتوى Light DOM
تتيح لك الفتحات (Slots) تمرير محتوى Light DOM
إلى داخل Shadow DOM
۔ إليك مثالاً:۔
1class MyElement extends HTMLElement {
2 constructor() {
3 super();
4 const shadow = this.attachShadow({ mode: 'open' });
5
6 shadow.innerHTML = `
7 <style>
8 .container {
9 border: 2px solid #ccc;
10 padding: 16px;
11 border-radius: 8px;
12 font-family: sans-serif;
13 }
14 .header {
15 font-size: 1.2em;
16 color: darkblue;
17 margin-bottom: 8px;
18 }
19 .content {
20 font-size: 1em;
21 color: #333;
22 }
23 </style>
24 <div class="container">
25 <div class="header">
26 <slot name="header"></slot>
27 </div>
28 <div class="content">
29 <slot name="content"></slot>
30 </div>
31 </div>
32 `;
33 }
34}
35
36customElements.define('my-element', MyElement);
يحتوي المستند الرئيسي على HTML بهذا الشكل:۔
1<my-element>
2 <h3 slot="header">Header Content</h1>
3 <p slot="content">Main Content</p>
4</my-element>
- يُظهر عنصر
slot
داخلShadow DOM
محتوىLight DOM
الذي يحمل سمةslot
المطابقة۔
الخاتمة
يُعتبر Shadow DOM
أداة أساسية لبناء مكونات ويب قوية وقابلة لإعادة الاستخدام وسهلة الصيانة۔ من خلال تغليف الأنماط والوظائف، يقلل من احتمال حدوث تعارضات ويُبسط إدارة قاعدة الشيفرة۔
يمكنك متابعة المقالة أعلاه باستخدام Visual Studio Code على قناتنا على YouTube.۔ يرجى التحقق من القناة على YouTube أيضًا.۔