परिचय
वेब कॉम्पोनेंट, आधुनिक स्टैंडर्ड का एक सेट है. इसकी मदद से:
- विजेट बनाने की सुविधा देना
- …जिन्हें भरोसेमंद तरीके से फिर से इस्तेमाल किया जा सकता है
- …और अगर कॉम्पोनेंट के अगले वर्शन में, अंदरूनी तौर पर हुए बदलावों की जानकारी बदलती है, तो इससे पेजों पर कोई असर नहीं पड़ेगा.
क्या इसका मतलब यह है कि आपको यह तय करना होगा कि एचटीएमएल/JavaScript का इस्तेमाल कब करना है और वेब कॉम्पोनेंट का इस्तेमाल कब करना है? नहीं! एचटीएमएल और JavaScript की मदद से, इंटरैक्टिव विज़ुअल कॉन्टेंट बनाया जा सकता है. विजेट, इंटरैक्टिव विज़ुअल होते हैं. विजेट बनाते समय, एचटीएमएल और JavaScript से जुड़ी अपनी स्किल का इस्तेमाल करना फ़ायदेमंद होता है. वेब कॉम्पोनेंट के स्टैंडर्ड, इस काम में आपकी मदद करने के लिए डिज़ाइन किए गए हैं.
हालांकि, एक बुनियादी समस्या है जिसकी वजह से एचटीएमएल और JavaScript से बनाए गए विजेट इस्तेमाल करना मुश्किल हो जाता है: विजेट के अंदर मौजूद डीओएम ट्री, पेज के बाकी हिस्से से अलग नहीं होता. एनकैप्सुलेशन की कमी का मतलब है कि आपकी दस्तावेज़ स्टाइलशीट, गलती से विजेट के अंदर के हिस्सों पर लागू हो सकती है. आपकी JavaScript, गलती से विजेट के अंदर के हिस्सों में बदलाव कर सकती है. आपके आईडी, विजेट के अंदर मौजूद आईडी से ओवरलैप हो सकते हैं. इसके अलावा, और भी समस्याएं हो सकती हैं.
वेब कॉम्पोनेंट के तीन हिस्से होते हैं:
शैडो डीओएम, डीओएम ट्री एनकैप्सुलेशन की समस्या को हल करता है. वेब कॉम्पोनेंट के चार हिस्सों को एक साथ काम करने के लिए डिज़ाइन किया गया है. हालांकि, आपके पास यह चुनने का विकल्प भी होता है कि वेब कॉम्पोनेंट के किन हिस्सों का इस्तेमाल करना है. इस ट्यूटोरियल में, शैडो DOM का इस्तेमाल करने का तरीका बताया गया है.
नमस्ते, शैडो वर्ल्ड
शैडो डीओएम की मदद से, एलिमेंट को उनसे जुड़ा एक नया नोड मिल सकता है. इस नए तरह के नोड को शैडो रूट कहा जाता है. जिस एलिमेंट के साथ शैडो रूट जुड़ा होता है उसे शैडो होस्ट कहा जाता है. शैडो होस्ट का कॉन्टेंट रेंडर नहीं होता है. इसके बजाय, शैडो रूट का कॉन्टेंट रेंडर होता है.
उदाहरण के लिए, अगर आपके पास इस तरह का मार्कअप है:
<button>Hello, world!</button>
<script>
var host = document.querySelector('button');
var root = host.createShadowRoot();
root.textContent = 'こんにちは、影の世界!';
</script>
इसके बाद,
<button id="ex1a">Hello, world!</button>
<script>
function remove(selector) {
Array.prototype.forEach.call(
document.querySelectorAll(selector),
function (node) { node.parentNode.removeChild(node); });
}
if (!HTMLElement.prototype.createShadowRoot) {
remove('#ex1a');
document.write('<img src="SS1.png" alt="Screenshot of a button with \'Hello, world!\' on it.">');
}
</script>
आपका पेज कैसा दिखता है
<button id="ex1b">Hello, world!</button>
<script>
(function () {
if (!HTMLElement.prototype.createShadowRoot) {
remove('#ex1b');
document.write('<img src="SS2.png" alt="Screenshot of a button with \'Hello, shadow world!\' in Japanese on it.">');
return;
}
var host = document.querySelector('#ex1b');
var root = host.createShadowRoot();
root.textContent = 'こんにちは、影の世界!';
})();
</script>
इतना ही नहीं, अगर पेज पर मौजूद JavaScript, बटन के textContent के बारे में पूछता है, तो उसे “こんにちは、影の世界!” नहीं, बल्कि “Hello, world!” मिलेगा. ऐसा इसलिए, क्योंकि शैडो रूट के नीचे मौजूद DOM सबट्री को एन्कैप्सुलेट किया गया है.
कॉन्टेंट को प्रज़ेंटेशन से अलग करना
अब हम कॉन्टेंट को प्रज़ेंटेशन से अलग करने के लिए, शैडो डीओएम का इस्तेमाल करने के बारे में जानेंगे. मान लें कि हमारे पास यह नेम टैग है:
<style>
.ex2a.outer {
border: 2px solid brown;
border-radius: 1em;
background: red;
font-size: 20pt;
width: 12em;
height: 7em;
text-align: center;
}
.ex2a .boilerplate {
color: white;
font-family: sans-serif;
padding: 0.5em;
}
.ex2a .name {
color: black;
background: white;
font-family: "Marker Felt", cursive;
font-size: 45pt;
padding-top: 0.2em;
}
</style>
<div class="ex2a outer">
<div class="boilerplate">
Hi! My name is
</div>
<div class="name">
Bob
</div>
</div>
यहां मार्कअप दिया गया है. आज आपको यह लिखना होगा. यह शैडो डीओएम का इस्तेमाल नहीं करता:
<style>
.outer {
border: 2px solid brown;
border-radius: 1em;
background: red;
font-size: 20pt;
width: 12em;
height: 7em;
text-align: center;
}
.boilerplate {
color: white;
font-family: sans-serif;
padding: 0.5em;
}
.name {
color: black;
background: white;
font-family: "Marker Felt", cursive;
font-size: 45pt;
padding-top: 0.2em;
}
</style>
<div class="outer">
<div class="boilerplate">
Hi! My name is
</div>
<div class="name">
Bob
</div>
</div>
डीओएम ट्री में एन्कैप्सुलेशन की सुविधा नहीं होती है. इसलिए, नेम टैग का पूरा स्ट्रक्चर दस्तावेज़ में दिखता है. अगर पेज पर मौजूद अन्य एलिमेंट, स्टाइलिंग या स्क्रिप्टिंग के लिए गलती से एक ही क्लास नेम का इस्तेमाल करते हैं, तो हमें परेशानी होगी.
हम बुरे समय से बच सकते हैं.
पहला चरण: प्रज़ेंटेशन की जानकारी छिपाना
सिमैंटिक तौर पर, हमें शायद सिर्फ़ इस बात की परवाह है कि:
- यह एक नेम टैग है.
- नाम “Bob” है.
सबसे पहले, हम ऐसा मार्कअप लिखते हैं जो हमारे हिसाब से सही सिमैंटिक के करीब हो:
<div id="nameTag">Bob</div>
इसके बाद, हम प्रज़ेंटेशन के लिए इस्तेमाल की गई सभी स्टाइल और div को <template> एलिमेंट में डालते हैं:
<div id="nameTag">Bob</div>
<template id="nameTagTemplate">
<span class="unchanged"><style>
.outer {
border: 2px solid brown;
… same as above …
</style>
<div class="outer">
<div class="boilerplate">
Hi! My name is
</div>
<div class="name">
Bob
</div>
</div></span>
</template>
इस समय, सिर्फ़ ‘Bob’ रेंडर होता है. हमने प्रज़ेंटेशनल डीओएम एलिमेंट को <template> एलिमेंट के अंदर मूव कर दिया है. इसलिए, वे रेंडर नहीं होते. हालांकि, उन्हें JavaScript से ऐक्सेस किया जा सकता है. शैडो रूट को पॉप्युलेट करने के लिए,
हम ऐसा करते हैं:
<script>
var shadow = document.querySelector('#nameTag').createShadowRoot();
var template = document.querySelector('#nameTagTemplate');
var clone = document.importNode(template.content, true);
shadow.appendChild(clone);
शैडो रूट सेट अप करने के बाद, नेम टैग को फिर से रेंडर किया जाता है. अगर नेम टैग पर राइट क्लिक करके एलिमेंट की जांच की जाए, तो आपको दिखेगा कि यह एक अच्छा और सिमैंटिक मार्कअप है:
<div id="nameTag">Bob</div>
इससे पता चलता है कि शैडो डीओएम का इस्तेमाल करके, हमने दस्तावेज़ से नेम टैग के प्रज़ेंटेशन की जानकारी छिपाई है. प्रज़ेंटेशन की जानकारी, शैडो डीओएम में एन्कैप्सुलेट की जाती है.
दूसरा चरण: कॉन्टेंट को प्रज़ेंटेशन से अलग करना
अब हमारा नेम टैग, पेज से प्रज़ेंटेशन की जानकारी छिपा देता है. हालांकि, यह प्रज़ेंटेशन को कॉन्टेंट से अलग नहीं करता. ऐसा इसलिए, क्योंकि कॉन्टेंट (नाम “बॉब”) पेज में मौजूद है, लेकिन रेंडर किया गया नाम वह है जिसे हमने शैडो रूट में कॉपी किया है. अगर हमें नेम टैग पर मौजूद नाम बदलना है, तो हमें दो जगहों पर बदलाव करना होगा. ऐसा हो सकता है कि वे सिंक न हों.
एचटीएमएल एलिमेंट कंपोज़िशनल होते हैं. उदाहरण के लिए, किसी टेबल में बटन डाला जा सकता है. हमें यहां कंपोज़िशन की ज़रूरत है: नेम टैग, लाल बैकग्राउंड, “नमस्ते!” टेक्स्ट, और नेम टैग पर मौजूद कॉन्टेंट का कंपोज़िशन होना चाहिए.
कॉम्पोनेंट के लेखक के तौर पर, आपको यह तय करना होगा कि आपके विजेट के साथ कंपोज़िशन कैसे काम करे. इसके लिए, <content> नाम के नए एलिमेंट का इस्तेमाल करें. इससे विजेट के प्रज़ेंटेशन में एक इंसर्शन पॉइंट बनता है. यह इंसर्शन पॉइंट, शैडो होस्ट से कॉन्टेंट चुनता है और उसे उस पॉइंट पर दिखाता है.
अगर हम शैडो डीओएम में मार्कअप को इस तरह बदलें:
<span class="unchanged"><template id="nameTagTemplate">
<style>
…
</style></span>
<div class="outer">
<div class="boilerplate">
Hi! My name is
</div>
<div class="name">
<content></content>
</div>
</div>
<span class="unchanged"></template></span>
जब नेम टैग रेंडर होता है, तो शैडो होस्ट का कॉन्टेंट उस जगह पर प्रोजेक्ट किया जाता है जहां <content> एलिमेंट दिखता है.
अब दस्तावेज़ का स्ट्रक्चर आसान हो गया है, क्योंकि नाम सिर्फ़ एक जगह पर है — दस्तावेज़ में. अगर आपको कभी अपने पेज पर उपयोगकर्ता का नाम अपडेट करना हो, तो बस यह लिखें:
document.querySelector('#nameTag').textContent = 'Shellie';
बस इतना ही. ब्राउज़र, नेम टैग की रेंडरिंग को अपने-आप अपडेट कर देता है. ऐसा इसलिए होता है, क्योंकि हम <content> की मदद से, नेम टैग के कॉन्टेंट को सही जगह पर प्रोजेक्ट कर रहे हैं.
<div id="ex2b">
अब हमने कॉन्टेंट और प्रज़ेंटेशन को अलग-अलग कर दिया है. कॉन्टेंट, दस्तावेज़ में है; प्रज़ेंटेशन, शैडो डीओएम में है. जब कुछ रेंडर करने का समय आता है, तो ब्राउज़र उन्हें अपने-आप सिंक रखता है.
तीसरा चरण: फ़ायदा
कॉन्टेंट और प्रज़ेंटेशन को अलग-अलग करके, हम कॉन्टेंट में बदलाव करने वाले
कोड को आसान बना सकते हैं. नेम टैग के उदाहरण में, उस
कोड को सिर्फ़
एक <div> वाले आसान स्ट्रक्चर के साथ काम करना होता है, न कि कई वाले स्ट्रक्चर के साथ.
अब अगर हम अपना प्रज़ेंटेशन बदलते हैं, तो हमें कोड में कोई बदलाव करने की ज़रूरत नहीं है!
उदाहरण के लिए, मान लें कि हमें अपने नाम टैग को स्थानीय भाषा में अनुवाद करना है. यह अब भी एक नेम टैग है. इसलिए, दस्तावेज़ में मौजूद सिमैंटिक कॉन्टेंट में कोई बदलाव नहीं होता:
<div id="nameTag">Bob</div>
शैडो रूट सेटअप कोड में कोई बदलाव नहीं होता. शैडो रूट में क्या डाला जाता है, यह बदल जाता है:
<template id="nameTagTemplate">
<style>
.outer {
border: 2px solid pink;
border-radius: 1em;
background: url(sakura.jpg);
font-size: 20pt;
width: 12em;
height: 7em;
text-align: center;
font-family: sans-serif;
font-weight: bold;
}
.name {
font-size: 45pt;
font-weight: normal;
margin-top: 0.8em;
padding-top: 0.2em;
}
</style>
<div class="outer">
<div class="name">
<content></content>
</div>
と申します。
</div>
</template>
यह वेब पर आज की स्थिति के मुकाबले काफ़ी बेहतर है, क्योंकि नाम अपडेट करने का कोड, कॉम्पोनेंट के स्ट्रक्चर पर निर्भर कर सकता है. यह स्ट्रक्चर आसान और एक जैसा होता है. नाम अपडेट करने वाले कोड को रेंडरिंग के लिए इस्तेमाल किए गए स्ट्रक्चर की जानकारी की ज़रूरत नहीं होती. अगर हम रेंडर किए गए टेक्स्ट को देखें, तो अंग्रेज़ी में नाम दूसरे नंबर पर दिखता है (“Hi! मेरा नाम है”), लेकिन जापानी भाषा में पहले (“と申します” से पहले). दिखाए जा रहे नाम को अपडेट करने के लिहाज़ से, यह अंतर सिमैंटिक तौर पर बेमतलब है. इसलिए, नाम अपडेट करने वाले कोड को इस बारे में जानने की ज़रूरत नहीं है.
अतिरिक्त क्रेडिट: ऐडवांस प्रोजेक्शन
ऊपर दिए गए उदाहरण में, <content> एलिमेंट, शैडो होस्ट से सारा कॉन्टेंट चुनता है. select एट्रिब्यूट का इस्तेमाल करके, यह कंट्रोल किया जा सकता है कि कॉन्टेंट एलिमेंट क्या प्रोजेक्ट करे. एक से ज़्यादा कॉन्टेंट एलिमेंट भी इस्तेमाल किए जा सकते हैं.
उदाहरण के लिए, अगर आपके पास कोई ऐसा दस्तावेज़ है जिसमें यह शामिल है:
<div id="nameTag">
<div class="first">Bob</div>
<div>B. Love</div>
<div class="email">bob@</div>
</div>
और एक शैडो रूट, जो खास कॉन्टेंट चुनने के लिए सीएसएस सिलेक्टर का इस्तेमाल करता है:
<div style="background: purple; padding: 1em;">
<div style="color: red;">
<content **select=".first"**></content>
</div>
<div style="color: yellow;">
<content **select="div"**></content>
</div>
<div style="color: blue;">
<content **select=".email">**</content>
</div>
</div>
<div class="email"> एलिमेंट, <content select="div"> और <content
select=".email">, दोनों एलिमेंट से मैच होता है. बॉब का ईमेल पता कितनी बार दिखता है और किन रंगों में?
इसका जवाब यह है कि बॉब का ईमेल पता एक बार दिखता है और वह पीले रंग का होता है.
इसकी वजह यह है कि शैडो डीओएम को हैक करने वाले लोगों को पता है कि स्क्रीन पर रेंडर होने वाले एलिमेंट का ट्री बनाना, एक बड़ी पार्टी की तरह है. कॉन्टेंट एलिमेंट एक न्योता है, जो दस्तावेज़ के कॉन्टेंट को बैकस्टेज शैडो डीओएम रेंडरिंग पार्टी में शामिल होने की अनुमति देता है. ये न्योते क्रम से डिलीवर किए जाते हैं. न्योता किसे मिलेगा, यह इस बात पर निर्भर करता है कि उसे किसे भेजा गया है. यानी, select एट्रिब्यूट की वैल्यू क्या है. न्योता मिलने पर, कॉन्टेंट हमेशा उसे स्वीकार करता है (कौन नहीं करेगा?!) और फिर वह चला जाता है. अगर उस पते पर फिर से न्योता भेजा जाता है, तो वह किसी को नहीं मिलेगा और वह व्यक्ति आपकी पार्टी में नहीं आएगा.
ऊपर दिए गए उदाहरण में, <div class="email">, div सिलेक्टर और .email सिलेक्टर, दोनों से मैच करता है. हालांकि, div सिलेक्टर वाला कॉन्टेंट एलिमेंट, दस्तावेज़ में पहले आता है. इसलिए, <div class="email">, पीले रंग की पार्टी में जाता है और नीले रंग की पार्टी में जाने के लिए कोई उपलब्ध नहीं होता. (शायद इसलिए यह इतना नीला है. हालांकि, दुख में साथी की ज़रूरत होती है, इसलिए कुछ कहा नहीं जा सकता.)
अगर किसी एलिमेंट को किसी भी पार्टी में शामिल होने का न्योता नहीं मिलता है, तो उसे रेंडर नहीं किया जाता. पहले उदाहरण में, “नमस्ते” टेक्स्ट के साथ ऐसा ही हुआ था. यह तब काम आता है, जब आपको बिलकुल अलग रेंडरिंग करनी हो: दस्तावेज़ में सिमैंटिक मॉडल लिखें, जिसे पेज में मौजूद स्क्रिप्ट ऐक्सेस कर सकें. हालांकि, रेंडरिंग के लिए इसे छिपाएं और JavaScript का इस्तेमाल करके, शैडो डीओएम में बिलकुल अलग रेंडरिंग मॉडल से कनेक्ट करें.
उदाहरण के लिए, एचटीएमएल में तारीख चुनने वाला एक अच्छा टूल है. <input
type="date"> लिखने पर, आपको एक पॉप-अप कैलेंडर दिखता है. लेकिन क्या होगा अगर आपको उपयोगकर्ता को अपने डेज़र्ट आइलैंड की छुट्टियों के लिए तारीखों की एक रेंज चुनने की अनुमति देनी हो (आपको पता है… रेड वाइन से बने झूलों के साथ.) अपने दस्तावेज़ को इस तरह सेट अप करें:
<div class="dateRangePicker">
<label for="start">Start:</label>
<input type="date" name="startDate" id="start">
<br>
<label for="end">End:</label>
<input type="date" name="endDate" id="end">
</div>
लेकिन शैडो डीओएम बनाएं, जो एक शानदार कैलेंडर बनाने के लिए टेबल का इस्तेमाल करता है. यह तारीखों की सीमा वगैरह को हाइलाइट करता है. जब उपयोगकर्ता कैलेंडर में मौजूद दिनों पर क्लिक करता है, तो कॉम्पोनेंट, startDate और endDate इनपुट में स्थिति को अपडेट करता है. जब उपयोगकर्ता फ़ॉर्म सबमिट करता है, तो उन इनपुट एलिमेंट की वैल्यू सबमिट हो जाती हैं.
अगर लेबल रेंडर नहीं होने वाले हैं, तो मैंने उन्हें दस्तावेज़ में क्यों शामिल किया? इसकी वजह यह है कि अगर कोई उपयोगकर्ता किसी ऐसे ब्राउज़र से फ़ॉर्म देखता है जो शैडो डीओएम के साथ काम नहीं करता, तो भी फ़ॉर्म का इस्तेमाल किया जा सकता है. हालांकि, वह उतना अच्छा नहीं दिखता. उपयोगकर्ता को कुछ ऐसा दिखता है:
<div class="dateRangePicker">
<label for="start">Start:</label>
<input type="date" name="startDate" id="start">
<br>
<label for="end">End:</label>
<input type="date" name="endDate" id="end">
</div>
आपने शैडो डीओएम 101 पास कर लिया है
यह शैडो डीओएम के बारे में बुनियादी जानकारी थी. आपने शैडो डीओएम के बारे में बुनियादी जानकारी हासिल कर ली है! शैडो डीओएम की मदद से और भी बहुत कुछ किया जा सकता है. उदाहरण के लिए, एक शैडो होस्ट पर कई शैडो का इस्तेमाल किया जा सकता है. इसके अलावा, एन्कैप्सुलेशन के लिए नेस्ट किए गए शैडो का इस्तेमाल किया जा सकता है. इसके अलावा, मॉडल-ड्रिवन व्यू (एमडीवी) और शैडो डीओएम का इस्तेमाल करके, अपने पेज को आर्किटेक्ट किया जा सकता है. वेब कॉम्पोनेंट, शैडो डीओएम से कहीं ज़्यादा हैं.
हम इनके बारे में बाद की पोस्ट में बताएंगे.