উন্নত ধারণা এবং DOM API
এই নিবন্ধটি শ্যাডো ডোমের সাথে আপনি করতে পারেন এমন আরও আশ্চর্যজনক জিনিস নিয়ে আলোচনা করে! এটি Shadow DOM 101 এবং Shadow DOM 201- এ আলোচিত ধারণাগুলির উপর ভিত্তি করে তৈরি করে।
একাধিক ছায়া শিকড় ব্যবহার করে
আপনি যদি একটি পার্টি হোস্ট করছেন, সবাই একই রুমে আটকে থাকলে এটি স্টাফ হয়ে যায়। আপনি একাধিক কক্ষ জুড়ে লোকেদের গ্রুপ বিতরণের বিকল্প চান। শ্যাডো ডম হোস্টিং এলিমেন্টগুলিও এটি করতে পারে, অর্থাৎ তারা এক সময়ে একাধিক শ্যাডো রুট হোস্ট করতে পারে।
চলুন দেখা যাক যদি আমরা একটি হোস্টের সাথে একাধিক শ্যাডো রুট সংযুক্ত করার চেষ্টা করি তাহলে কি হবে:
<div id="example1">Light DOM</div>
<script>
var container = document.querySelector('#example1');
var root1 = container.createShadowRoot();
var root2 = container.createShadowRoot();
root1.innerHTML = '<div>Root 1 FTW</div>';
root2.innerHTML = '<div>Root 2 FTW</div>';
</script>
"রুট 2 FTW" যা রেন্ডার করে, তা সত্ত্বেও আমরা ইতিমধ্যে একটি ছায়া গাছ সংযুক্ত করেছি। কারণ শেষ ছায়া গাছ একটি হোস্ট যোগ করা হয়েছে, জয়ী হয়. রেন্ডারিংয়ের ক্ষেত্রে এটি একটি LIFO স্ট্যাক। DevTools পরীক্ষা করা এই আচরণটি যাচাই করে।
তাহলে রেন্ডারিং পার্টিতে শুধুমাত্র শেষটিকে আমন্ত্রণ জানানো হলে একাধিক ছায়া ব্যবহার করে কী লাভ? ছায়া সন্নিবেশ পয়েন্ট লিখুন.
ছায়া সন্নিবেশ পয়েন্ট
"শ্যাডো ইনসার্টেশন পয়েন্ট" ( <shadow>
) সাধারণ সন্নিবেশ পয়েন্ট ( <content>
) এর মতো যে তারা স্থানধারক। যাইহোক, হোস্টের সামগ্রীর জন্য স্থানধারক হওয়ার পরিবর্তে, তারা অন্যান্য ছায়া গাছের জন্য হোস্ট। এটা শ্যাডো ডম ইনসেপশন!
আপনি সম্ভবত কল্পনা করতে পারেন, আপনি খরগোশের গর্তটি যতই ড্রিল করবেন ততই জিনিসগুলি আরও জটিল হয়ে উঠবে। এই কারণে, একাধিক <shadow>
উপাদানগুলি খেলার সময় কী ঘটে সে সম্পর্কে স্পেকটি খুব স্পষ্ট:
আমাদের মূল উদাহরণের দিকে ফিরে তাকালে, প্রথম ছায়া root1
আমন্ত্রণ তালিকা থেকে বেরিয়ে গেছে। একটি <shadow>
সন্নিবেশ বিন্দু যোগ করা এটিকে ফিরিয়ে আনে:
<div id="example2">Light DOM</div>
<script>
var container = document.querySelector('#example2');
var root1 = container.createShadowRoot();
var root2 = container.createShadowRoot();
root1.innerHTML = '<div>Root 1 FTW</div><content></content>';
**root2.innerHTML = '<div>Root 2 FTW</div><shadow></shadow>';**
</script>
এই উদাহরণ সম্পর্কে কিছু আকর্ষণীয় জিনিস আছে:
- "রুট 2 FTW" এখনও "রুট 1 FTW" এর উপরে রেন্ডার করে। এই কারণে যে আমরা
<shadow>
সন্নিবেশ বিন্দু স্থাপন করেছি। আপনি যদি বিপরীত চান, সন্নিবেশ বিন্দু সরান:root2.innerHTML = '<shadow></shadow><div>Root 2 FTW</div>';
. - লক্ষ্য করুন রুট1-এ এখন একটি
<content>
সন্নিবেশ বিন্দু রয়েছে। এটি রেন্ডারিং রাইডের জন্য টেক্সট নোড "হালকা DOM" কে বরাবর আসে।
<shadow>
এ কি রেন্ডার করা হয়?
কখনও কখনও এটি একটি <shadow>
এ রেন্ডার করা হচ্ছে পুরানো ছায়া গাছ জানতে দরকারী। আপনি .olderShadowRoot
এর মাধ্যমে সেই গাছটির একটি রেফারেন্স পেতে পারেন:
**root2.olderShadowRoot** === root1 //true
একটি হোস্ট এর ছায়া রুট প্রাপ্তি
যদি কোনো উপাদান Shadow DOM হোস্ট করে থাকে তাহলে আপনি .shadowRoot
ব্যবহার করে এর কনিষ্ঠতম শ্যাডো রুট অ্যাক্সেস করতে পারবেন:
var root = host.createShadowRoot();
console.log(host.shadowRoot === root); // true
console.log(document.body.shadowRoot); // null
আপনি যদি লোকেদের আপনার ছায়ায় প্রবেশ করার বিষয়ে চিন্তিত হন, তাহলে .shadowRoot
শূন্য করার জন্য পুনরায় সংজ্ঞায়িত করুন:
Object.defineProperty(host, 'shadowRoot', {
get: function() { return null; },
set: function(value) { }
});
একটি হ্যাক একটি বিট, কিন্তু এটি কাজ করে. শেষ পর্যন্ত, এটি মনে রাখা গুরুত্বপূর্ণ যে আশ্চর্যজনকভাবে চমত্কার হলেও, ছায়া DOM একটি নিরাপত্তা বৈশিষ্ট্য হিসাবে ডিজাইন করা হয়নি ৷ সম্পূর্ণ বিষয়বস্তু বিচ্ছিন্নতার জন্য এটির উপর নির্ভর করবেন না।
JS-এ ছায়া DOM তৈরি করা
আপনি যদি JS-এ DOM তৈরি করতে পছন্দ করেন, HTMLContentElement
এবং HTMLShadowElement
এর জন্য ইন্টারফেস আছে।
<div id="example3">
<span>Light DOM</span>
</div>
<script>
var container = document.querySelector('#example3');
var root1 = container.createShadowRoot();
var root2 = container.createShadowRoot();
var div = document.createElement('div');
div.textContent = 'Root 1 FTW';
root1.appendChild(div);
// HTMLContentElement
var content = document.createElement('content');
content.select = 'span'; // selects any spans the host node contains
root1.appendChild(content);
var div = document.createElement('div');
div.textContent = 'Root 2 FTW';
root2.appendChild(div);
// HTMLShadowElement
var shadow = document.createElement('shadow');
root2.appendChild(shadow);
</script>
এই উদাহরণটি প্রায় আগের অনুচ্ছেদে অনুরূপ। শুধুমাত্র পার্থক্য হল যে এখন আমি নতুন যোগ করা <span>
বের করতে select
ব্যবহার করছি।
সন্নিবেশ পয়েন্ট সঙ্গে কাজ
যে নোডগুলি হোস্ট এলিমেন্ট থেকে নির্বাচন করা হয় এবং শ্যাডো ট্রিতে "ডিস্ট্রিবিউট" করা হয় তাকে বলা হয়…ড্রামরোল…ডিস্ট্রিবিউটেড নোড! সন্নিবেশ পয়েন্ট তাদের আমন্ত্রণ জানালে ছায়ার সীমানা অতিক্রম করার অনুমতি দেওয়া হয়।
সন্নিবেশ পয়েন্ট সম্পর্কে ধারণাগতভাবে উদ্ভট বিষয় হল যে তারা শারীরিকভাবে DOM সরায় না। হোস্টের নোডগুলি অক্ষত থাকে। সন্নিবেশ পয়েন্ট শুধুমাত্র হোস্ট থেকে ছায়া গাছের মধ্যে নোড পুনরায় প্রকল্প. এটি একটি উপস্থাপনা/রেন্ডারিং জিনিস: "এই নোডগুলি এখানে সরান" "এই অবস্থানে এই নোডগুলি রেন্ডার করুন।"
যেমন:
<div><h2>Light DOM</h2></div>
<script>
var root = document.querySelector('div').createShadowRoot();
root.innerHTML = '<content select="h2"></content>';
var h2 = document.querySelector('h2');
console.log(root.querySelector('content[select="h2"] h2')); // null;
console.log(root.querySelector('content').contains(h2)); // false
</script>
ভয়লা ! h2
ছায়া DOM-এর সন্তান নয়। এটি অন্য টিড বিটের দিকে নিয়ে যায়:
Element.getDistributedNodes()
আমরা একটি <content>
এ যেতে পারি না, কিন্তু .getDistributedNodes()
API আমাদেরকে একটি সন্নিবেশ বিন্দুতে বিতরণ করা নোডগুলিকে জিজ্ঞাসা করতে দেয়:
<div id="example4">
<h2>Eric</h2>
<h2>Bidelman</h2>
<div>Digital Jedi</div>
<h4>footer text</h4>
</div>
<template id="sdom">
<header>
<content select="h2"></content>
</header>
<section>
<content select="div"></content>
</section>
<footer>
<content select="h4:first-of-type"></content>
</footer>
</template>
<script>
var container = document.querySelector('#example4');
var root = container.createShadowRoot();
var t = document.querySelector('#sdom');
var clone = document.importNode(t.content, true);
root.appendChild(clone);
var html = [];
[].forEach.call(root.querySelectorAll('content'), function(el) {
html.push(el.outerHTML + ': ');
var nodes = el.getDistributedNodes();
[].forEach.call(nodes, function(node) {
html.push(node.outerHTML);
});
html.push('\n');
});
</script>
Element.getDestinationInsertionPoints()
.getDistributedNodes()
এর মতো, আপনি .getDestinationInsertionPoints()
কল করে একটি নোডকে কোন সন্নিবেশ পয়েন্টে বিতরণ করা হয়েছে তা পরীক্ষা করতে পারেন:
<div id="host">
<h2>Light DOM
</div>
<script>
var container = document.querySelector('div');
var root1 = container.createShadowRoot();
var root2 = container.createShadowRoot();
root1.innerHTML = '<content select="h2"></content>';
root2.innerHTML = '<shadow></shadow>';
var h2 = document.querySelector('#host h2');
var insertionPoints = h2.getDestinationInsertionPoints();
[].forEach.call(insertionPoints, function(contentEl) {
console.log(contentEl);
});
</script>
টুল: শ্যাডো ডম ভিজ্যুয়ালাইজার
শ্যাডো ডোম যে কালো জাদু বোঝা কঠিন। আমি প্রথমবার এটির চারপাশে আমার মাথা মোড়ানোর চেষ্টা করেছি মনে আছে।
Shadow DOM রেন্ডারিং কীভাবে কাজ করে তা কল্পনা করতে সাহায্য করার জন্য, আমি d3.js ব্যবহার করে একটি টুল তৈরি করেছি। বাম দিকের উভয় মার্কআপ বাক্স সম্পাদনাযোগ্য। নির্দ্বিধায় আপনার নিজস্ব মার্কআপে পেস্ট করুন এবং কীভাবে জিনিসগুলি কাজ করে এবং সন্নিবেশ পয়েন্টগুলি হোস্ট নোডগুলিকে ছায়া গাছে স্যুইজ করে তা দেখতে চারপাশে খেলুন৷
এটা একবার চেষ্টা করে দেখুন এবং আপনি কি মনে করেন তা আমাকে জানান!
ইভেন্ট মডেল
কিছু ঘটনা ছায়া সীমা অতিক্রম করে এবং কিছু ঘটনা ঘটে না। যে ক্ষেত্রে ঘটনাগুলি সীমানা অতিক্রম করে, সেই ক্ষেত্রে ইভেন্ট টার্গেটটি এনক্যাপসুলেশন বজায় রাখার জন্য সামঞ্জস্য করা হয় যা ছায়া রুটের উপরের সীমানা প্রদান করে। অর্থাৎ, ইভেন্টগুলিকে রিটার্গেট করা হয় যেন তারা হোস্ট এলিমেন্ট থেকে এসেছে, অভ্যন্তরীণ উপাদান থেকে Shadow DOM-এ এসেছে ।
প্লে অ্যাকশন ১
- এই এক আকর্ষণীয়. আপনি হোস্ট উপাদান (
<div data-host>
) থেকে নীল নোডে একটিmouseout
দেখতে পাবেন। যদিও এটি একটি বিতরণ করা নোড, এটি এখনও হোস্টে রয়েছে, ShadowDOM নয়। আবার হলুদে মাউস করার ফলে নীল নোডে একটিmouseout
হয়।
প্লে অ্যাকশন 2
- একটি
mouseout
আছে যা হোস্টে প্রদর্শিত হয় (খুব শেষে)। সাধারণত আপনি সমস্ত হলুদ ব্লকের জন্যmouseout
ইভেন্ট ট্রিগার দেখতে পাবেন। যাইহোক, এই ক্ষেত্রে এই উপাদানগুলি ছায়া DOM-এর অভ্যন্তরীণ এবং ইভেন্টটি তার উপরের সীমানা দিয়ে বুদবুদ করে না।
প্লে অ্যাকশন 3
- লক্ষ্য করুন যে আপনি যখন ইনপুটে ক্লিক করেন,
focusin
ইনপুটে প্রদর্শিত হয় না বরং হোস্ট নোডেই প্রদর্শিত হয়। এটাকে রিটার্গেট করা হয়েছে!
যে ঘটনাগুলো সবসময় বন্ধ থাকে
নিম্নলিখিত ঘটনাগুলি ছায়ার সীমানা অতিক্রম করে না:
- গর্ভপাত
- ত্রুটি
- নির্বাচন করুন
- পরিবর্তন
- লোড
- রিসেট
- আকার পরিবর্তন করুন
- স্ক্রল
- শুরু নির্বাচন করুন
উপসংহার
আমি আশা করি আপনি একমত হবেন যে Shadow DOM অবিশ্বাস্যভাবে শক্তিশালী । প্রথমবারের মতো, <iframe>
s বা অন্যান্য পুরানো কৌশলগুলির অতিরিক্ত ব্যাগেজ ছাড়াই আমাদের যথাযথ এনক্যাপসুলেশন আছে।
শ্যাডো ডম অবশ্যই জটিল প্রাণী, তবে এটি ওয়েব প্ল্যাটফর্মে যোগ করার মতো একটি প্রাণী। এর সাথে কিছু সময় কাটান। এটা শিখুন. প্রশ্ন করুন।
আপনি যদি আরও জানতে চান, ডমিনিকের ভূমিকা নিবন্ধটি দেখুন Shadow DOM 101 এবং আমার ছায়া DOM 201: CSS এবং স্টাইলিং নিবন্ধ।