Intro untuk Shadow DOM
Indonesian (Bahasa Indonesia) translation by Dendi Deden (you can also view the original English article)
Ambil halaman web modern dan Anda akan melihat bahwa hal itu selalu berisi konten yang dijahit bersama-sama dari berbagai sumber yang berbeda; ini mungkin termasuk berbagi sosial widget dari Twitter atau Facebook atau video Youtube bermain widget, mungkin melayani iklan hasil personalisasi dari beberapa server iklan atau dapat mencakup beberapa utilitas script atau style dari perpustakaan pihak ketiga host lebih di CDN dan seterusnya. Dan jika semuanya HTML berbasis (seperti pilihan hari ini) ada probabilitas tinggi tabrakan antara markup, script atau style yang disajikan dari berbagai sumber. Umumnya, namespaces bekerja untuk mencegah ini tabrakan yang memecahkan masalah sampai batas tertentu, tetapi mereka tidak menawarkan enkapsulasi.
Enkapsulasi adalah salah satu pilar yang paradigma Object Oriented Programming dan biasanya digunakan untuk membatasi internal representasi dari object dari dunia luar.
Kembali ke masalah kami, kami pasti dapat merangkum kode JavaScript menggunakan closures atau menggunakan module pattern tapi apa bisa kita lakukan semua ini untuk HTML markup? Bayangkan bahwa kita harus membangun sebuah widget UI, apa bisa kita sembunyikan rincian implementasi widget dari kode JavaScript dan CSS yang terdapat pada halaman, yang mengkonsumsi widget kami? Selain itu, kami dapat mencegah kode memakan dari mengacaukan widget kami fungsi atau tampilan dan nuansa?
Shadow DOM datan untuk menyelamatkan
Satu-satunya solusi yang ada yang menciptakan batas antara kode Anda menulis dan kode yang mengkonsumsi, jelek - dan beroperasi dengan menggunakan iFrame besar dan ketat, yang membawa dengan itu sendiri satu set masalah. Jadi kita dipaksa untuk beradaptasi dengan pendekatan ini selalu?
Tidak lagi! Shadow DOM memberikan kita cara yang elegan untuk tampilan subtree DOM normal dengan dokumen khusus yang berisi lain subtree node, yang ditembus skrip dan style. Bagian yang menarik adalah bahwa itu bukanlah sesuatu yang baru! Berbagai browser telah menggunakan metodologi ini untuk menerapkan widget native seperti tanggal, Slider, audio, video player, dll.
Mengaktifkan Shadow DOM
Pada saat ini ditulis, versi saat ini dari Chrome (v29) mendukung inspecting Shadpw DOM menggunakan Chrome DevTools. Buka Devtools dan klik pada cog tombol di kanan bawah layar untuk membuka Settings panel, scroll ke bawah sedikit dan Anda akan melihat sebuah checkbox untuk menampilkan Shadow DOM.



Sekarang bahwa kita mengaktifkan browser kami, mari kita periksa internal pemutar audio default. Ketikkan:
1 |
<audio width="300" height="32" src="http://developer.mozilla.org/@api/deki/files/2926/=AudioTest_(1).ogg" autoplay="autoplay" controls="controls"> |
2 |
Your browser does not support the HTML5 Audio. |
3 |
</audio>
|
Ke markup HTML Anda. Itu menunjukkan pemutar audio native berikut dalam browser yang didukung:

Sekarang pergi ke depan dan memeriksa widget pemutar audio yang baru Anda buat.



Wow! Ini menunjukkan representasi internal pemutar audio, yang dimana tersembunyi. Seperti yang kita lihat, elemen audio menggunakan document fragment untuk mengadakan internal isi widget dan menambahkan untuk wadah elemen (yang dikenal sebagai Sahdow Host).
Shadow Host & Shadow Root
- Shadow Host: adalah elemen DOM yang menjadi host subtree
Shadow DOM
atau DOM node yang berisi Shadow Root. - Shadow Root: root DOM subtree mengandung Shadow DOM node. Ini adalah sebuah node yang khusus, yang menciptakan batas antara normal DOM node dan shadow DOM node. Ini adalah batas ini, yang mengenkapsulasi Shadow DOM node dari setiap JavaScript atau CSS kode pada halaman cosuming.
- Shadow DOM: memungkinkan untuk beberapa DOM subtrees akan terdiri ke satu tree yang lebih besar. Berikut gambar dari rancangan kerja W3C terbaik menjelaskan konsep overlaying node. Ini adalah bagaimana tampilannya sebelum Shadoww Root konten disertakan elemen Shadow Host:
Ketika dirender, Shadow tree berlangsung Shadow Host konten.
Proses overlaying node sering disebut sebagai komposisi.
- Shadow Boundary: dilambangkan dengan garis putus-putus pada gambar diatas. Ini menandakan pemisahan antara dunia DOM normal dan Shadow DOM dunia. Script dari kedua sisi tidak dapat menyeberangi batas ini dan menciptakan kekacauan di sisi lain.
Halo Shadow DOM dunia
Cukup chit-chat saya katakan, mari kita mendapatkan tangan kita kotor dengan menulis beberapa kode. Misalkan kita memiliki markup berikut, yang menunjukkan pesan pembuka yang sederhana.
1 |
<div id="welcomeMessage">Welcome to My World</div> |
Tambahkan kode JavaScript berikut atau menggunakan Fiddle ini:
1 |
var shadowHost = document.querySelector("#welcomeMessage"); |
2 |
var shadowRoot = shadowHost.webkitCreateShadowRoot(); |
3 |
shadowRoot.textContent = "Hello Shadow DOM World"; |
Di sini kita membuat sebuah Shadow Root yang menggunakan webkitCreateShadowRoot()
fungsi, pasangkan ke Shadow host dan kemudian hanya mengubah konten.
Perhatikan webkit
awalan khusus vendor sebelum nama fungsi. Hal ini menunjukkan bahwa fungsi ini didukung pada beberapa browser yang hanya berbasis webkit.
Jika Anda pergi ke depan dan menjalankan contoh ini dalam browser yang didukung, maka Anda akan melihat "Hello Shadow DOM World" bukan "Selamat datang to My World" sebagai Shadow DOM node memiliki over-shadowed yang biasa.
Penangkalan: Seperti beberapa dari Anda mungkin memperhatikan, kami sedang mencampur markup dengan script, yang umumnya tidak dianjurkan dan Shadow DOM tidak terkecuali. Kami sengaja menghindari penggunaan template begitu awal dalam permainan untuk menghindari kebingungan. Sebaliknya Shadow DOM menyediakan solusi elegan untuk masalah ini dan kita akan sampai di sana cukup segera.
Menghormati Shadow Boundary
Jika Anda mencoba dan mengakses konten yang merender tree menggunakan JavaScript, seperti:
1 |
var shadowHost = document.querySelector("#welcomeMessage"); |
2 |
var shadowRoot = shadowHost.webkitCreateShadowRoot(); |
3 |
shadowRoot.textContent = "Hello Shadow DOM World"; |
4 |
|
5 |
console.log(shadowHost.textContent); |
6 |
// Prints "Welcome to My World" as the shadow DOM nodes are encapsulated and cannot be accessed by JavaScript |
Anda akan mendapatkan asli konten "Welcome to My World" dan bukan konten yang sebenarnya dituliskan pada halaman, seperti Shadow DOM tree yang dienkapsulasi dari script apapun. Ini juga berarti bahwa widget yang Anda buat menggunakan Shaodow DOM aman dari setiap script yang tidak diinginkan/bertentangan yang sudah ada di halaman.
Style enkapsulasi
Demikian pula, semua CSS selector dilarang untuk menyeberangi shadow boundary. Periksa kode berikut di mana kita telah diterapkan warna merah daftar item, tetapi bahwa style hanya diterapkan ke node yang merupakan bagian dari halaman parent, dan daftar item yang merupakan bagian dari Shadow Root tidak terpengaruh dengan style ini.
1 |
<div class="outer"> |
2 |
<div id="welcomeMessage">Welcome to My World</div> |
3 |
<div class="normalTree">Sample List |
4 |
<ul>
|
5 |
<li>Item 1</li> |
6 |
<li>Item 2</li> |
7 |
</ul>
|
8 |
</div>
|
9 |
</div>
|
10 |
<style>
|
11 |
div.outer li { |
12 |
color: red; |
13 |
}
|
14 |
div.outer{ |
15 |
border: solid 1px; padding: 1em; |
16 |
}
|
17 |
</style>
|
18 |
<script type="text/javascript"> |
19 |
var shadowHost = document.querySelector("#welcomeMessage"); |
20 |
var shadowRoot = shadowHost.webkitCreateShadowRoot(); |
21 |
shadowRoot.innerHTML = ["<div class='shadowChild'>", |
22 |
"Shadow DOM offers us Encapsulation from", |
23 |
"<ul>", |
24 |
"<li>Scripts</li>", |
25 |
"<li>Styles</li>", |
26 |
"</ul>", |
27 |
"</div>" |
28 |
].join(',').replace(/,/g,""); |
29 |
</script>
|
Anda dapat melihat kode langsung di Fiddle. Enkapsulasi ini berlaku bahkan jika kita membalikkan arah traversal. Setiap style yang didefinisikan di dalam Shadow DOM tidak mempengaruhi dokumen parent dan tetap scoped hanya ke Shadow Root. Periksa Fiddle ini untuk contoh, dimana kita menerapkan warna biru untuk daftar item dalam Shadow DOM tetapi dokumen parent daftar item tidak terpengaruh.
Namun ada satu pengecualian di sini; Shadow DOM memberikan kita fleksibilitas untuk style Shadow Host, DOM node yang memegang Shadlw DOM. idealnya terletak di luar Shadow boundary dan bukan bagian dari Shadow Root, tetapi menggunakan aturan @host
, satu dapat menentukan style yang dapat diterapkan ke Shadow Host seperti kita memiliki style pesan pembuka dalam contoh di bawah ini.
1 |
<div id="welcomeMessage">Welcome to My World</div> |
2 |
<script type="text/javascript"> |
3 |
var shadowHost = document.querySelector("#welcomeMessage"); |
4 |
var shadowRoot = shadowHost.webkitCreateShadowRoot(); |
5 |
shadowRoot.innerHTML = ["<style>", |
6 |
"@host{ ", |
7 |
"#welcomeMessage{ ", |
8 |
"font-size: 28px;", |
9 |
"font-family:cursive;", |
10 |
"font-weight:bold;", |
11 |
"}", |
12 |
"}", |
13 |
"</style>", |
14 |
"<content select=''></content>" |
15 |
].join(',').replace(/,/g,""); |
16 |
</script>
|
Periksa Fiddle ini seperti kita style pesan pembuka Shadow Host menggunakan style yang didefinisikan dalam Shadow DOM.
Menciptakan Style Hook
Sebagai pengembang widget, saya mungkin ingin pengguna widget saya mampu untuk style elemen tertentu. Hal ini dicapai dengan memasukkan lubang ke shadow boundary menggunakan kustom pseudo elemen. Hal ini mirip dengan bagaimana beberapa browser membuat style hook untuk pengembang untuk dstyle beberapa unsur-unsur internal widget native. Misalnya, untuk style jempol dan jalur native slider Anda dapat menggunakan ::- webkit-slider-thumb
dan ::webkit-slider-runnable-track
sebagai berikut:
1 |
input[type=range]{ |
2 |
-webkit-appearance:none; |
3 |
}
|
4 |
input[type=range]::-webkit-slider-thumb { |
5 |
-webkit-appearance:none; |
6 |
height:12px; |
7 |
width:12px; |
8 |
border-radius:6px; |
9 |
background:yellow; |
10 |
position:relative; |
11 |
top:-5px; |
12 |
}
|
13 |
input[type=range]::-webkit-slider-runnable-track { |
14 |
background:red; |
15 |
height:2px; |
16 |
}
|
Fork Fiddle ini dan menerapkan Style Anda sendiri untuk itu!
Event penargetan kembali
Jika suatu event yang berasal dari salah satu node dalam Shadow DOM melintasi Shadow Boundary kemudian kembali ditujukan untuk merujuk kepada Shadow Host untuk menjaga enkapsulasi. Pertimbangkan kode berikut:
1 |
<input id="normalText" type="text" value="Normal DOM Text Node" /> |
2 |
<div id="shadowHost"></div> |
3 |
<input id="shadowText" type="text" value="Shadow DOM Node" /> |
4 |
<script type="text/javascript"> |
5 |
var shadowHost = document.querySelector('#shadowHost'); |
6 |
var shadowRoot = shadowHost.webkitCreateShadowRoot(); |
7 |
var template = document.querySelector('template'); |
8 |
shadowRoot.appendChild(template.content.cloneNode(true)); |
9 |
template.remove(); |
10 |
document.addEventListener('click', function(e) { |
11 |
console.log(e.target.id + ' clicked!'); |
12 |
});
|
13 |
</script>
|
Ini merender elemen-elemen dua input teks, satu melalui Normal DOM dan lain melalui Shadow DOM dan kemudian mendengarkan event click
pada document
. Sekarang, ketika input teks kedua diklik, event ini berasal dari dalam Shadow DOM dan ketika melintasi Shadow Boundary, event yang dimodifikasi untuk mengubah elemen target ke Shaodw Host<div>
elemen bukan<input>
masukan teks. Kami juga telah memperkenalkan elemen <template>
baru di sini; ini secara konseptual mirip dengan sisi klien template solusi seperti Handlerbars dan Underscores tetapi tidak seperti yang berkembang dan tidak memiliki dukungan browser. Karena itu, menggunakan template adalah cara ideal untuk menulis Shadow DOM daripada menggunakan tag script seperti yang telah dilakukan sejauh seluruh artikel ini.
pemisahan kepentingan
Kita sudah tahu bahwa itu adalah selalu ide yang baik untuk memisahkan konten sebenarnya dari presentasi; Shadow DOM tidak harus menanamkan konten apapun, yang akhirnya akan ditampilkan kepada pengguna. Sebaliknya, konten selalu harus hadir pada halaman original dan tidak tersembunyi di dalam template Shadow DOM. Ketika terjadi komposisi, konten ini harus kemudian diproyeksikan ke titik penyisipan tepat didefinisikan dalam template Shadow DOM. Mari kita menulis ulang contoh Hello World, menjaga dalam pikiran di atas pemisahan - sebuah contoh live dapat ditemukan di Fiddle.
1 |
<div id="welcomeMessage">Welcome to Shadow DOM World</div> |
2 |
<script type="text/javascript"> |
3 |
var shadowRoot = document.querySelector("#welcomeMessage").webkitCreateShadowRoot(); |
4 |
var template = document.querySelector("template"); |
5 |
shadowRoot.appendChild(template.content); |
6 |
template.remove(); |
7 |
</script>
|
Ketika halaman dirender, isi dari Shadow Host diproyeksikan ke tempat dimana <content>
elemen muncul. Ini adalah contoh yang sangat sederhana di mana <content>
mengambil segala sesuatu di dalam Shadow Host selama komposisi. Tapi itu sangat baik bisa selektif dalam memilih konten dariShadow Host menggunakan atribut select
seperti yang ditunjukkan di bawah ini
1 |
<div id="outer">How about some cool demo, eh ? |
2 |
<div class="cursiveButton">My Awesome Button</div> |
3 |
</div>
|
4 |
<button>
|
5 |
Fallback Content |
6 |
</button>
|
7 |
<style>
|
8 |
button{ |
9 |
font-family: cursive; |
10 |
font-size: 24px; |
11 |
color: red; |
12 |
}
|
13 |
</style>
|
14 |
<script type="text/javascript"> |
15 |
var shadowRoot = document.querySelector("#outer").webkitCreateShadowRoot(); |
16 |
var template = document.querySelector("template"); |
17 |
shadowRoot.appendChild(template.content.cloneNode(true)); |
18 |
template.remove(); |
19 |
</script>
|
Coba live demo dan bermain dengan itu untuk lebih memahami konsep penyisipan poin dan proyeksi.
Komponen-komponen Web
Seperti Anda mungkin sudah tahu, Shadow DOM adalah bagian dari Web komponen Spec, yang menawarkan fitur lain yang rapi, seperti:
- Template - digunakan untuk menahan inert markup, yang akan digunakan pada titik kemudian dalam waktu. Oleh inert, kita berarti bahwa semua gambar di markup tidak download, termasuk script tidak hadir sampai konten template benar-benar menjadi bagian dari halaman.
- Dekorator - digunakan untuk menerapkan template yang didasarkan pada CSS selector dan karenanya dapat dilihat sebagai dekorasi elemen yang ada dengan meningkatkan presentasi mereka.
- Impor HTML - memberikan kita kemampuan untuk menggunakan kembali dokumen HTML lainnya dalam dokumen kami tanpa secara eksplisit membuat panggilan XHR dan menulis event handler untuk itu.
- Elemen Kustom - memungkinkan kita untuk menentukan jenis elemen HTML baru yang kemudian dapat digunakan declaratively di markup. Misalnya, jika Anda ingin untuk membuat widget navigasi Anda sendiri, Anda menetapkan elemen navigasi Anda, mewarisi dari HTMLElement dan menyediakan callback life-ctyle tertentu yang menerapkan event-event tertentu seperti konstruksi, mengubah, penghancuran widget dan hanya menggunakan widget di markup Anda sebagai
<myAwesomeNavigation attr1="value1" ..=""> </myAwesomeNavigation>
. jadi kustom elemen pada dasarnya memberi kita cara untuk bundel semua Shadow DOM naguc, menyembunyikan rincian internal dan paket segala sesuatu bersama-sama.
Saya tidak akan babble banyak tentang aspek-aspek lain dari Web komponen Spec dalam artikel ini, tetapi itu akan melakukan kita baik untuk mengingat bahwa bersama-sama mereka memungkinkan kita untuk membuat widget UI dapat digunakan kembali yang portabel di browser dalam tampilan dan nuansa dan sepenuhnya dikemas dengan semua skrip d style dari halaman yang dipakai.
Kesimpulan
Spesifikasi komponen Web sedang dikerjakan dan kode contoh termasuk yang bekerja hari ini mungkin tidak bekerja pada rilis berikutnya. Sebagai contoh, teks-teks yang sebelumnya pada subjek ini menggunakan metode webkitShadowRoot()
yang tidak lagi bekerja; Sebaliknya gunakan createWebkitShadowRoot()
untuk membuat sebuah Shadow Root. Jadi jika Anda ingin menggunakan ini untuk membuat beberapa demo keren menggunakan Shadwo DOM, selalu terbaik untuk merujuk pada spesifikasi untuk rincian.
Saat ini, hanya Chrome dan Opera yang mendukungnya sehingga saya akan berhati-hati tentang termasuk setiap Shadow DOM saya instance produksi, tetapi dengan Google keluar dengan Polymer yang dibangun di atas Web komponen dan Polyfills keluar untuk mendukung Shadow DOM secara Native, ini adalah pasti sesuatu yang setiap web developer harus mendapatkan tangan kotor dengannya.
Anda juga dapat tetap diperbarui dengan hal terbaru di Shadow DOM dengan mengikuti saluran Google+ ini. Juga checkout Shadow DOM Visualizer tool, yang membantu Anda untuk memvisualisasikan bagaimana Shaodow DOM dirender dalam browser.