Gölge DOM, web geliştiricilerinin bölümlere ayrılmış DOM ve web bileşenleri için CSS oluşturmasına olanak tanır
Özet
Gölge DOM, web uygulaması oluşturmanın kırılganlığını ortadan kaldırır. Kırılganlık
HTML, CSS ve JS'nin küresel doğasından gelir. Yıllar içinde
fahiş bir sayı icat etti
/
araçlar
nasıl yardımcı olabileceğini
açıklayacağız. Örneğin, yeni bir HTML kimliği/sınıfı kullandığınızda
sayfa tarafından kullanılan mevcut adla çakışıp çakışmayacağı belli değildir.
Küçük hatalar kayabilir,
CSS spesifikliği büyük bir soruna dönüşüyor (!important
her şey dahil!), stil
seçiciler kontrolden çıkacaktır
performans düşebilir. Liste
bu şekilde devam eder.
Gölge DOM, CSS ve DOM'yi düzeltir. Web'de kapsamlı stiller sunar platformu. Araçlar veya adlandırma kuralları olmadan CSS'yi işaretleme, uygulama ayrıntılarını gizleme ve yazma kontrolü bileşenleri hakkında daha fazla bilgi edinin.
Giriş
Gölge DOM, üç Web Bileşeni standardından biridir: HTML Şablonları, Shadow DOM ve Özel öğeler. HTML İçe Aktarma İşlemleri eskiden listede yer alıyordu ancak artık kullanımdan kaldırıldı.
Gölge DOM kullanan web bileşenleri oluşturmanız gerekmez. Ancak böyle yaptığınızda avantajlarından (CSS kapsamı, DOM kapsülleme, bileşimi) ve tekrar kullanılabilir özel öğeleri kullanıyorsanız dayanıklı, yüksek düzeyde yapılandırılabilir ve son derece yeniden kullanılabilir. Özelse öğeleri yeni bir HTML (JS API ile) oluşturmak için kullanılır. Gölge DOM, nasıl kullandığınıza bağlı olarak değişir. İki API birleşerek bir bileşen oluşturur HTML, CSS ve JavaScript kodu kullanabilirsiniz.
Gölge DOM, bileşen tabanlı uygulamalar oluşturmak için bir araç olarak tasarlanmıştır. Dolayısıyla, web geliştirmede sık karşılaşılan sorunlar için çözümler sunar:
- Yalıtılmış DOM: Bileşenin DOM'u bağımsızdır (ör.
document.querySelector()
, bileşenin gölge DOM'sindeki düğümleri döndürmez. - Kapsamlı CSS: Gölge DOM'de tanımlanan CSS'nin kapsamındadır. Stil kuralları ve sayfa stilleri taşmaz.
- Yapı: Bileşeniniz için bildirim temelli, işaretleme tabanlı bir API tasarlayın.
- CSS'yi basitleştirir: Kapsamlı DOM, basit CSS seçicileri ve daha fazlasını kullanabileceğiniz anlamına gelir genel kimlik/sınıf adlarına dikkat etmeniz ve adlandırma çakışmaları konusunda endişelenmenize gerek yoktur.
- Üretkenlik: Uygulamaları tek bir büyük yerine DOM parçaları halinde düşünün (global) sayfasına gidin.
fancy-tabs
demosu
Bu makale boyunca, demo bileşeninden (<fancy-tabs>
) bahsedeceğim.
ve kod snippet'lerini referans göstermekle daha iyi olur. Tarayıcınız API'leri destekliyorsa
hemen aşağıda bunun canlı bir demosunu göreceksiniz. Aksi takdirde tam kaynağa GitHub'dan bakın.
Gölge DOM nedir?
DOM arka planı
HTML, kullanımı kolay olduğu için web'i destekler. Birkaç etiket tanımlayarak hem sunum hem de yapı içeren bir sayfayı saniyeler içinde oluşturabilirsiniz. Ancak, tek başına HTML pek faydalı değildir. İnsanlar bir metni kolayca anlayabilir. makinelerin daha fazlasına ihtiyacı var. Belge Nesnesi'ni girin Model veya DOM.
Tarayıcı bir web sayfasını yüklediğinde birçok ilginç şey yapar. Şunlardan biri: yaptığı şey, yazarın HTML'sini canlı bir dokümana dönüştürmektir. Temel olarak, sayfanın yapısını anlamak için tarayıcı, HTML'yi (statik) metin dizeleri) veri modeline (nesneler/düğümler) dönüştürür. Tarayıcı, HTML'nin hiyerarşisi için şu düğümlerden bir ağaç oluşturun: DOM. Harika şey hakkında önemli olan, sayfanızın canlı bir temsili olmasıdır. Statik Bizim yazdığımız HTML, tarayıcı tarafından üretilen düğümler, özellikleri, yöntemleri ve en iyi programlar tarafından manipüle edilebildiğini unutmamak gerekir! Bu nedenle DOM oluşturabiliyoruz. öğelerini doğrudan JavaScript kullanarak oluşturabilirsiniz:
const header = document.createElement('header');
const h1 = document.createElement('h1');
h1.textContent = 'Hello DOM';
header.appendChild(h1);
document.body.appendChild(header);
aşağıdaki HTML işaretlemesini oluşturur:
<body>
<header>
<h1>Hello DOM</h1>
</header>
</body>
Her şey yolunda ve güzel olsun. Sonra gölge DOM nedir?
DOM... gölgelerde
Gölge DOM, iki farkı olan normal bir DOM'dur: 1) Nasıl oluşturulduğu/kullanıldığı ve
2) sayfanın geri kalanına kıyasla nasıl davrandığı. Normalde, bir DOM
bunları başka bir öğenin alt öğeleri olarak ekleyin. Gölge DOM ile
öğeye bağlı olan, ancak öğeden ayrı olarak kapsamlı bir DOM ağacı oluşturun
gerçek çocuklardır. Kapsamı belirlenmiş bu alt ağaç, gölge ağacı olarak adlandırılır. Element
gölge ana makinesi olur. Gölgeye eklediğiniz her şey
<style>
dahil olmak üzere barındırma öğesinde yereldir. Gölge DOM bu şekildedir
CSS stil kapsamı elde eder.
Gölge DOM oluşturuluyor
Gölge kökü, bir "ana makine" öğesine eklenen bir belge parçasıdır.
Gölge kökü ekleme işlemi, öğenin gölge DOM'sini nasıl edindiğidir. Alıcı:
bir öğe için gölge DOM'u oluşturun, element.attachShadow()
çağrısı yapın:
const header = document.createElement('header');
const shadowRoot = header.attachShadow({mode: 'open'});
shadowRoot.innerHTML = '<h1>Hello Shadow DOM</h1>'; // Could also use appendChild().
// header.shadowRoot === shadowRoot
// shadowRoot.host === header
Gölge kökünü doldurmak için .innerHTML
kullanıyorum ancak başka DOM de kullanabilirsiniz
API'ler. Bu web. Seçme şansımız var.
Bu spesifikasyon, bir öğe listesini tanımlar barındıramaz. Bir öğenin şu listede:
- Tarayıcı, öğe için zaten kendi dahili gölge DOM'sini barındırıyor
(
<textarea>
,<input>
). - Öğenin bir gölge DOM'u (
<img>
) barındırması anlamlı değildir.
Örneğin, şu yöntem işe yaramaz:
document.createElement('input').attachShadow({mode: 'open'});
// Error. `<input>` cannot host shadow dom.
Özel bir öğe için gölge DOM'u oluşturma
Gölge DOM, özel öğelerle ilişkilidir. Bir öğenin HTML, CSS ve JS'sini bölümlere ayırmak için gölge DOM'yi kullanın. "web bileşeni" oluşturabilirsiniz.
Örnek - özel bir öğe kendisine gölge DOM'u ekler, DOM/CSS'yi kapsülleme:
// Use custom elements API v1 to register a new HTML tag and define its JS behavior
// using an ES6 class. Every instance of <fancy-tab> will have this same prototype.
customElements.define('fancy-tabs', class extends HTMLElement {
constructor() {
super(); // always call super() first in the constructor.
// Attach a shadow root to <fancy-tabs>.
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<style>#tabs { ... }</style> <!-- styles are scoped to fancy-tabs! -->
<div id="tabs">...</div>
<div id="panels">...</div>
`;
}
...
});
Burada bazı ilginç şeyler oluyor. İlki,
<fancy-tabs>
örneği olduğunda özel öğe kendi gölge DOM'sini oluşturur
ile başlar. Bu işlem constructor()
içinde yapılabilir. İkincisi, yeni kullanıcılar için
bir gölge kökü olursa <style>
içindeki CSS kurallarının kapsamı <fancy-tabs>
olur.
Beste ve alanlar
Kompozisyon, gölge DOM'un en az anlaşılan özelliklerinden biridir. Ancak muhtemelen en önemlisi.
Web geliştirme dünyamızda beste, uygulamaları oluşturma şeklimizdir.
bildiriyor. Farklı yapı taşları (<div>
'ler, <header>
'lar,
<form>
ve <input>
olmak üzere) bir araya gelerek uygulama oluşturabilir. Bu etiketlerin bazıları
bir iletişim kurmaktır. Kompozisyonun nedeni, <select>
,
<details>
, <form>
ve <video>
çok esnek. Bu etiketlerin her biri
özel bir işlem gerçekleştirir. Örneğin,
<select>
, <option>
ve <optgroup>
öğelerini açılır menüde nasıl oluşturacağını biliyor ve
widget'ları otomatik olarak devreye sokun. <details>
öğesi <summary>
öğesini
genişletilebilir ok. <video>
bile bazı çocuklarla nasıl başa çıkacağını biliyor:
<source>
öğeleri oluşturulmaz ancak videonun davranışını etkiler.
Ne sihir!
Terminoloji: ışık DOM'u ve gölge DOM'u
Gölge DOM bileşimi, web'de birçok yeni temel ilkeyi kullanıma sunar bahsedeceğim. Konuya girmeden önce aynı dili konuşuyoruz.
Hafif DOM
Bileşeninizin bir kullanıcısının yazdığı işaretleme. Bu DOM, gölge DOM'sini eklemeniz gerekir. Öğenin gerçek alt öğeleridir.
<better-button>
<!-- the image and span are better-button's light DOM -->
<img src="gear.svg" slot="icon">
<span>Settings</span>
</better-button>
Gölge DOM
Bir bileşen yazarının yazdığı DOM. Gölge DOM, bileşende yereldir ve dahili yapısını, kapsamlı CSS'sini tanımlar ve uygulamanızı içerir bolca fırsat sunuyor. Ayrıca, tüketici tarafından yazılan işaretlemenin nasıl oluşturulacağını da tanımlayabilir hakkında daha fazla bilgi edinin.
#shadow-root
<style>...</style>
<slot name="icon"></slot>
<span id="wrapper">
<slot>Button</slot>
</span>
Düzleştirilmiş DOM ağacı
Tarayıcının, kullanıcının ışık DOM'sini gölgenize dağıtmasının sonucu DOM, nihai ürünü oluşturuyor. Düzülmüş ağaç, nihai olarak tepeden tırnağa ve sayfada nelerin oluşturulduğunu görebilirsiniz.
<better-button>
#shadow-root
<style>...</style>
<slot name="icon">
<img src="gear.svg" slot="icon">
</slot>
<span id="wrapper">
<slot>
<span>Settings</span>
</slot>
</span>
</better-button>
<slot> öğe
Gölge DOM, <slot>
öğesini kullanarak farklı DOM ağaçları oluşturur.
Alanlar, bileşeninizin içindeki, kullanıcıların
kendi işaretlemenizi kullanın. Bir veya daha fazla alan tanımlayarak dış işaretlemeyi oluşturmaya davet edersiniz.
API'yi kullanabilirsiniz. Sonuç olarak, "Kullanıcının
işaretleyin".
Öğelerin "çapraz" olmasına izin verilir <slot>
tarafından davet edildiğinde gölge DOM
inceleyebilirsiniz. Bu öğelere dağıtılmış düğümler adı verilir. Kavramsal olarak
dağıtılmış düğümler biraz tuhaf görünebilir. Slotlar DOM'yi fiziksel olarak taşımaz; onlar
gölge DOM'nin içindeki başka bir konumda oluşturun.
Bir bileşen, gölge DOM'sinde sıfır veya daha fazla alan tanımlayabilir. Slot boş olabilir veya yedek içerik sağlayın. Kullanıcı hafif DOM sağlamazsa alan, yedek içeriği oluşturur.
<!-- Default slot. If there's more than one default slot, the first is used. -->
<slot></slot>
<slot>fallback content</slot> <!-- default slot with fallback content -->
<slot> <!-- default slot entire DOM tree as fallback -->
<h2>Title</h2>
<summary>Description text</summary>
</slot>
Ayrıca adlandırılmış alanlar da oluşturabilirsiniz. Adlandırılmış alanlar, kullanıcıların adıyla başvurduğu gölge DOM.
Örnek - <fancy-tabs>
gölge DOM'sindeki alanlar:
#shadow-root
<div id="tabs">
<slot id="tabsSlot" name="title"></slot> <!-- named slot -->
</div>
<div id="panels">
<slot id="panelsSlot"></slot>
</div>
Bileşen kullanıcıları, <fancy-tabs>
öğesini aşağıdaki şekilde beyan ediyor:
<fancy-tabs>
<button slot="title">Title</button>
<button slot="title" selected>Title 2</button>
<button slot="title">Title 3</button>
<section>content panel 1</section>
<section>content panel 2</section>
<section>content panel 3</section>
</fancy-tabs>
<!-- Using <h2>'s and changing the ordering would also work! -->
<fancy-tabs>
<h2 slot="title">Title</h2>
<section>content panel 1</section>
<h2 slot="title" selected>Title 2</h2>
<section>content panel 2</section>
<h2 slot="title">Title 3</h2>
<section>content panel 3</section>
</fancy-tabs>
Merak ediyorsanız, düzleştirilmiş ağaç aşağıdaki gibi görünür:
<fancy-tabs>
#shadow-root
<div id="tabs">
<slot id="tabsSlot" name="title">
<button slot="title">Title</button>
<button slot="title" selected>Title 2</button>
<button slot="title">Title 3</button>
</slot>
</div>
<div id="panels">
<slot id="panelsSlot">
<section>content panel 1</section>
<section>content panel 2</section>
<section>content panel 3</section>
</slot>
</div>
</fancy-tabs>
Bileşenimizin farklı yapılandırmaları işleyebildiğine dikkat edin, ancak
düzleştirilmiş DOM ağacı aynı kalır. İsterseniz <button>
yerine
<h2>
. Bu bileşen, farklı alt öğeleri işlemek için geliştirilmiştir...
aynı <select>
gibi!
Stil
Web bileşenlerinin stil özelliklerini ayarlamak için pek çok seçenek vardır. Gölge kullanan bir bileşen DOM, ana sayfa tarafından stillandırılabilir, kendi stillerini tanımlayabilir veya kancalar ( CSS özel özellikleri) biçimindedir.
Bileşen tanımlı stiller
Gölge DOM'un en yararlı özelliği kapsamlı CSS'dir:
- Dış sayfadaki CSS seçiciler, bileşeninizin içinde geçerli değildir.
- İçeride tanımlanan stillere aktarılamaz. Barındırıcı öğesine ayarlanırlar.
Gölge DOM'sinde kullanılan CSS seçiciler bileşeninize yerel olarak uygulanır. İçinde Böylece, endişe duymadan yaygın kimlik/sınıf adlarını tekrar kullanabiliriz. çakışmalarla ilgili daha fazla bilgi verir. En iyi uygulama, daha basit CSS seçicileri kullanmaktır inceleyebilirsiniz. Ayrıca, performans için de iyidir.
Örnek: Bir gölge kökünde tanımlanan stiller yereldir
#shadow-root
<style>
#panels {
box-shadow: 0 2px 2px rgba(0, 0, 0, .3);
background: white;
...
}
#tabs {
display: inline-flex;
...
}
</style>
<div id="tabs">
...
</div>
<div id="panels">
...
</div>
Stil sayfaları gölge ağacına da ayarlanır:
#shadow-root
<link rel="stylesheet" href="styles.css">
<div id="tabs">
...
</div>
<div id="panels">
...
</div>
<select>
öğesinin çoklu seçimli bir widget'ı (
açılır menüden) multiple
özelliğini eklediğinizde:
<select multiple>
<option>Do</option>
<option selected>Re</option>
<option>Mi</option>
<option>Fa</option>
<option>So</option>
</select>
<select>
, kullandığınız özelliklere göre kendisini farklı şekillerde biçimlendirebiliyor
açıklamam gerekiyor. Web bileşenleri, :host
öğesini kullanarak kendilerini de biçimlendirebilir.
kullanabilirsiniz.
Örnek: Kendisine stil veren bir bileşen
<style>
:host {
display: block; /* by default, custom elements are display: inline */
contain: content; /* CSS containment FTW. */
}
</style>
:host
ile elde edilen sorunlardan biri, üst sayfadaki kuralların daha belirgin olmasıdır.
öğede tanımlanan :host
kuraldan daha fazladır. Yani dış stiller kazanır. Bu
kullanıcıların üst düzey stilinizi dışarıdan geçersiz kılmasına olanak tanır. Ayrıca :host
yalnızca bir gölge kökü bağlamında çalıştığından bunu
gölge DOM'yi belirtir.
:host(<selector>)
işlevinin işlevsel biçimi, şu durumlarda ana makineyi hedeflemenize olanak tanır:
<selector>
ile eşleşiyor. Bu, bileşeninizin en iyi uygulamaları göstermesi için
durumlara veya stil özelliklerine bağlı olarak dahili düğümlerin nasıl stil
ana makinede.
<style>
:host {
opacity: 0.4;
will-change: opacity;
transition: opacity 300ms ease-in-out;
}
:host(:hover) {
opacity: 1;
}
:host([disabled]) { /* style when host has disabled attribute. */
background: grey;
pointer-events: none;
opacity: 0.4;
}
:host(.blue) {
color: blue; /* color host when it has class="blue" */
}
:host(.pink) > #tabs {
color: pink; /* color internal #tabs node when host has class="pink". */
}
</style>
Bağlama göre stil belirleme
:host-context(<selector>)
, bileşen veya üst öğelerinden biri varsa bileşenle eşleşir
<selector>
ile eşleşiyor. Bunun yaygın bir kullanımı, bileşenin özelliklerine göre tema oluşturmak
teşekkür ederiz. Örneğin, birçok kişi bir sınıfa uygulayarak
<html>
veya <body>
:
<body class="darktheme">
<fancy-tabs>
...
</fancy-tabs>
</body>
:host-context(.darktheme)
, bir alt öğe olduğunda <fancy-tabs>
stilini biçimlendirir
/ .darktheme
:
:host-context(.darktheme) {
color: white;
background: black;
}
:host-context()
, tema oluşturmak için faydalı olabilir ancak
CSS özel özelliklerini kullanarak stil kancaları oluşturun.
Dağıtılmış düğümlerin stilini belirleme
::slotted(<compound-selector>)
, bir
<slot>
.
Bir ad rozeti bileşeni oluşturduğumuzu varsayalım:
<name-badge>
<h2>Eric Bidelman</h2>
<span class="title">
Digital Jedi, <span class="company">Google</span>
</span>
</name-badge>
Bileşenin gölge DOM'u, kullanıcının <h2>
ve .title
öğelerini biçimlendirebilir:
<style>
::slotted(h2) {
margin: 0;
font-weight: 300;
color: red;
}
::slotted(.title) {
color: orange;
}
/* DOESN'T WORK (can only select top-level nodes).
::slotted(.company),
::slotted(.title .company) {
text-transform: uppercase;
}
*/
</style>
<slot></slot>
Daha önce hatırlarsanız <slot>
'ler kullanıcının ışık DOM'sini taşımaz. Zaman
düğümler bir <slot>
içine dağıtılırsa <slot>
onların DOM'sini oluşturur, ancak
düğümler fiziksel olarak yerinde kalır. Dağıtımdan önce uygulanan stiller
geçerlidir. Bununla birlikte, ışık DOM'u dağıtıldığında tüm
ek stiller (gölge DOM'si tarafından tanımlananlar) alır.
<fancy-tabs>
sitesinden daha kapsamlı başka bir örnek:
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<style>
#panels {
box-shadow: 0 2px 2px rgba(0, 0, 0, .3);
background: white;
border-radius: 3px;
padding: 16px;
height: 250px;
overflow: auto;
}
#tabs {
display: inline-flex;
-webkit-user-select: none;
user-select: none;
}
#tabsSlot::slotted(*) {
font: 400 16px/22px 'Roboto';
padding: 16px 8px;
...
}
#tabsSlot::slotted([aria-selected="true"]) {
font-weight: 600;
background: white;
box-shadow: none;
}
#panelsSlot::slotted([aria-hidden="true"]) {
display: none;
}
</style>
<div id="tabs">
<slot id="tabsSlot" name="title"></slot>
</div>
<div id="panels">
<slot id="panelsSlot"></slot>
</div>
`;
Bu örnekte, sekme başlıkları için adlandırılmış bir alan ve
sekme paneli içeriği için bir alan. Bir kullanıcı bir sekme seçtiğinde seçimini kalın hale getiririz
panelini açın. Bu, aynı boyuta sahip dağıtılmış düğümler seçerek
selected
özelliği için de kullanılmaktadır. Özel öğenin JS'si (burada gösterilmez),
.
Bir bileşeni dışarıdan şekillendirme
Dışarıdan bir bileşene stil eklemenin birkaç yolu vardır. En kolay yöntemi, etiket adını seçici olarak kullanmaktır:
fancy-tabs {
width: 500px;
color: red; /* Note: inheritable CSS properties pierce the shadow DOM boundary. */
}
fancy-tabs:hover {
box-shadow: 0 3px 3px #ccc;
}
Dış stiller her zaman gölge DOM'de tanımlanan stillere karşı kazanır. Örneğin,
kullanıcı fancy-tabs { width: 500px; }
seçiciyi yazarsa bu seçici öne çıkar
bileşenin kuralı: :host { width: 650px;}
.
Bileşenin kendisine stil kazandırmak yeterli olacaktır. Peki ya bir bileşenin dahili bileşenlerini mi ayarlamak istiyorsunuz? Bunun için CSS'deki özel özellikler.
CSS özel özelliklerini kullanarak stil kancaları oluşturma
Bileşenin yazarı stil özellikleri sağlarsa kullanıcılar dahili stilleri düzenleyebilir
CSS özel özelliklerini kullanarak. Kavramsal olarak,
<slot>
"Stil yer tutucuları" oluşturursunuz kullanıcıların geçersiz kılmasına izin verir.
Örnek - <fancy-tabs>
, kullanıcıların arka plan rengini geçersiz kılmasına izin verir:
<!-- main page -->
<style>
fancy-tabs {
margin-bottom: 32px;
--fancy-tabs-bg: black;
}
</style>
<fancy-tabs background>...</fancy-tabs>
Gölge DOM'sinin içinde:
:host([background]) {
background: var(--fancy-tabs-bg, #9E9E9E);
border-radius: 10px;
padding: 10px;
}
Bu durumda, bileşen arka plan değeri olarak black
kullanacaktır.
tarafından sağlanmıştı. Aksi takdirde varsayılan olarak #9E9E9E
kullanılır.
İleri düzey konular
Kapalı gölge kökleri oluşturma (kaçınılması gerekir)
Gölge DOM'nin "closed" adlı başka bir türü daha vardır. yatırım yapmanız önemlidir. Bir
JavaScript'in dahili DOM'ye erişmesi mümkün olmadığı sürece,
hakkında daha fazla bilgi edinin. Bu, <video>
gibi yerel öğelerin çalışma şekline benzer.
JavaScript, <video>
gölge DOM'sine erişemiyor çünkü tarayıcı
kapalı mod gölge kökü kullanarak uygular.
Örnek: Kapalı gölge ağacı oluşturma:
const div = document.createElement('div');
const shadowRoot = div.attachShadow({mode: 'closed'}); // close shadow tree
// div.shadowRoot === null
// shadowRoot.host === div
Kapalı moddan diğer API'ler de etkilenir:
Element.assignedSlot
/TextNode.assignedSlot
,null
tarihinde iade ediliyor- Gölge içindeki öğelerle ilişkili etkinlikler için
Event.composedPath()
DOM, şunu döndürür: []
İşte size neden
{mode: 'closed'}
:
Yapay güvenlik duygusu. Bir saldırganı hiçbir şey
Element.prototype.attachShadow
hesabının ele geçirilmesi.Kapalı mod, özel öğe kodunuzun kendi koduna erişmesini engeller gölge DOM'yi eklemeniz gerekir. Tamamen başarısız oldu. Bunun yerine referans saklamanız gerekir
querySelector()
gibi araçları kullanmak istiyorsanız bundan daha sonra). Bu tamamen kapalı modun asıl amacına aykırıdır.customElements.define('x-element', class extends HTMLElement { constructor() { super(); // always call super() first in the constructor. this._shadowRoot = this.attachShadow({mode: 'closed'}); this._shadowRoot.innerHTML = '<div class="wrapper"></div>'; } connectedCallback() { // When creating closed shadow trees, you'll need to stash the shadow root // for later if you want to use it again. Kinda pointless. const wrapper = this._shadowRoot.querySelector('.wrapper'); } ... });
Kapalı mod, bileşeninizi son kullanıcılar için daha az esnek hale getirir. Siz bir kod eklemeyi unuttuğunuzda, özelliğini kullanabilirsiniz. Yapılandırma seçeneğidir. Kullanıcının istediği bir kullanım alanı. Yaygın bir dahili düğümler için yeterli biçimlendirme kancası eklemeyi unutmak olabilir. Kapalı modda, kullanıcıların varsayılanları geçersiz kılıp stillerini ayarlayın. Bileşenin dahili bilgilerine erişebilmek son derece faydalıdır. Sonuç olarak, kullanıcılar bileşeninizi çatallanır, başka bir bileşen bulur veya kendi bileşenlerini istediklerini yapmazsa sahip olur :(
JS'deki alanlarla çalışma
Gölge DOM API'si, slotlarla ve dağıtılmış özelliklerle çalışma düğüm. Özel öğe yazarken bunlar kullanışlıdır.
zaman aralığı değişikliği etkinliği
Bir alanın dağıtılmış düğümleri değiştiğinde slotchange
etkinliği tetiklenir. Örneğin,
Örneğin, kullanıcı ışık DOM'sine alt öğe ekler/kaldırırsa.
const slot = this.shadowRoot.querySelector('#slot');
slot.addEventListener('slotchange', e => {
console.log('light dom children changed!');
});
.
Işık DOM'de yapılan diğer değişiklik türlerini izlemek için
MutationObserver
oluşturmanız gerekir.
Bir alanda hangi öğeler oluşturuluyor?
Bazen bir alanla hangi öğelerin ilişkilendirildiğini bilmek yararlı olur. Telefonla arama
Alanın hangi öğeleri oluşturduğunu bulmak için slot.assignedNodes()
tuşlarına basın. İlgili içeriği oluşturmak için kullanılan
{flatten: true}
seçeneği, bir alanın yedek içeriğini de döndürür (hiçbir düğüm yoksa)
dağıtılıyor).
Örnek olarak, gölge DOM'nizin aşağıdaki gibi göründüğünü varsayalım:
<slot><b>fallback content</b></slot>
Kullanım | Telefon | Sonuç |
---|---|---|
<my-component>bileşen metni</my-component> | slot.assignedNodes(); |
[component text] |
<my-component></my-component> | slot.assignedNodes(); |
[] |
<my-component></my-component> | slot.assignedNodes({flatten: true}); |
[<b>fallback content</b>] |
Bir öğe hangi alana atanır?
Ters soruyu yanıtlamak da mümkündür. element.assignedSlot
anlatıyor
öğenizin hangi bileşen alanlarına atandığını görebilirsiniz.
Gölge DOM etkinlik modeli
Bir etkinlik gölge DOM'de dışarı çıktığında hedefi, gölge DOM'un sağladığı kapsülleme. Yani etkinlikler, daha iyi performans elde etmek için ve Google Analytics 4'teki dahili öğeler yerine bileşenden gölge DOM'yi belirtir. Bazı etkinlikler gölge DOM'den dışarı yayılmaz bile.
Gölge sınırını geçen etkinlikler şunlardır:
- Odaklanılan Etkinlikler:
blur
,focus
,focusin
,focusout
- Fare Etkinlikleri:
click
,dblclick
,mousedown
,mouseenter
,mousemove
vb. - Çark Etkinlikleri:
wheel
- Giriş Etkinlikleri:
beforeinput
,input
- Klavye Etkinlikleri:
keydown
,keyup
- Beste Etkinlikleri:
compositionstart
,compositionupdate
,compositionend
- DragEvent:
dragstart
,drag
,dragend
,drop
vb.
İpuçları
Gölge ağacı açıksa event.composedPath()
işlevinin çağrılması bir dizi döndürür
düğümlerin bulunduğu bir URL'dir.
Özel etkinlikleri kullanma
Bir gölge ağacındaki dahili düğümlerde tetiklenen özel DOM etkinlikleri
etkinlik
composed: true
işareti:
// Inside <fancy-tab> custom element class definition:
selectTab() {
const tabs = this.shadowRoot.querySelector('#tabs');
tabs.dispatchEvent(new Event('tab-select', {bubbles: true, composed: true}));
}
composed: false
(varsayılan) ise tüketiciler etkinliği dinleyemez
gölge kökünüzün dışına çıkar.
<fancy-tabs></fancy-tabs>
<script>
const tabs = document.querySelector('fancy-tabs');
tabs.addEventListener('tab-select', e => {
// won't fire if `tab-select` wasn't created with `composed: true`.
});
</script>
Odaklanma
Gölge DOM'nin etkinlik modelinden hatırlarsanız, tetiklenen etkinlikler
içlerindeki gölge DOM'u, barındırma öğesinden geliyormuş gibi görünecek şekilde ayarlanır.
Örneğin, gölge kökü içindeki bir <input>
öğesini tıkladığını varsayalım:
<x-focus>
#shadow-root
<input type="text" placeholder="Input inside shadow dom">
focus
etkinliği <input>
alanından değil, <x-focus>
alanından gelmiş gibi görünecek.
Benzer şekilde, document.activeElement
<x-focus>
olacak. Gölge kökü
mode:'open'
ile oluşturulduysa (kapalı mod konusuna bakın)
odaklanılan dahili düğüme erişebilir:
document.activeElement.shadowRoot.activeElement // only works with open mode.
Birden fazla gölge DOM'u seviyesi varsa (ör.
bir özel öğe varsa) gölge köklerini yinelemeli olarak ayrıntılı şekilde
activeElement
öğesini bul:
function deepActiveElement() {
let a = document.activeElement;
while (a && a.shadowRoot && a.shadowRoot.activeElement) {
a = a.shadowRoot.activeElement;
}
return a;
}
Odaklanmak için kullanabileceğiniz bir diğer seçenek de delegatesFocus: true
seçeneğidir. Bu seçenek
gölge ağacındaki öğenin odak davranışı:
- Gölge DOM'nin içindeki bir düğümü tıklarsanız ve düğüm odaklanılabilir bir alan değilse odaklanılabilir hale gelir.
- Gölge DOM'sinin içindeki bir düğüm odağını elde ettiğinde
:focus
, odaklanılan öğedir.
Örnek - delegatesFocus: true
ürününün odak davranışını nasıl değiştirdiği
<style>
:focus {
outline: 2px solid red;
}
</style>
<x-focus></x-focus>
<script>
customElements.define('x-focus', class extends HTMLElement {
constructor() {
super(); // always call super() first in the constructor.
const root = this.attachShadow({mode: 'open', delegatesFocus: true});
root.innerHTML = `
<style>
:host {
display: flex;
border: 1px dotted black;
padding: 16px;
}
:focus {
outline: 2px solid blue;
}
</style>
<div>Clickable Shadow DOM text</div>
<input type="text" placeholder="Input inside shadow dom">`;
// Know the focused element inside shadow DOM:
this.addEventListener('focus', function(e) {
console.log('Active element (inside shadow dom):',
this.shadowRoot.activeElement);
});
}
});
</script>
Sonuç
Yukarıda <x-focus>
odaklanıldığında sonuç gösterilir (kullanıcı tıklaması, sekmeyle
focus()
vb.), "Tıklanabilir Gölge DOM metni" veya dahili
<input>
odaklanılmış (autofocus
dahil).
delegatesFocus: false
özelliğini ayarlamış olsaydınız bunun yerine şunu görecektiniz:
İpuçları ve Püf Noktaları
Yıllar içinde web bileşenleri yazma hakkında birkaç şey öğrendim. İ bu ipuçlarından bazılarını bileşen yazma konusunda faydalı bulacağınızı düşünüyorum gölge DOM'de hata ayıklama.
CSS kapsamı kullanma
Genelde, bir web bileşeninin düzeni/stil/boyası yeterince bağımsızdır. Tekliflerinizi otomatikleştirmek ve optimize etmek için
Performans için :host
bölgesinde CSS kapsamı
kazan:
<style>
:host {
display: block;
contain: content; /* Boom. CSS containment FTW. */
}
</style>
Devralınabilir stiller sıfırlanıyor
Devralınabilir stiller (background
, color
, font
, line-height
vb.) devam ediyor
gölge DOM'den devralmak için de kullanılabilir. Yani gölge DOM sınırını
varsayılandır. Yeni bir seçenek listesiyle başlamak istiyorsanız sıfırlamak için all: initial;
komutunu kullanın
devralınabilir stilleri gölge sınırını geçtiklerinde başlangıç değerlerine ekler.
<style>
div {
padding: 10px;
background: red;
font-size: 25px;
text-transform: uppercase;
color: white;
}
</style>
<div>
<p>I'm outside the element (big/white)</p>
<my-element>Light DOM content is also affected.</my-element>
<p>I'm outside the element (big/white)</p>
</div>
<script>
const el = document.querySelector('my-element');
el.attachShadow({mode: 'open'}).innerHTML = `
<style>
:host {
all: initial; /* 1st rule so subsequent properties are reset. */
display: block;
background: white;
}
</style>
<p>my-element: all CSS properties are reset to their
initial value using <code>all: initial</code>.</p>
<slot></slot>
`;
</script>
Bir sayfanın kullandığı tüm özel öğeleri bulma
Bazen sayfada kullanılan özel öğeleri bulmak yararlı olur. Bunun için, sayfada kullanılan tüm öğelerin gölge DOM'sini yinelemeli olarak çekmesi gerekir.
const allCustomElements = [];
function isCustomElement(el) {
const isAttr = el.getAttribute('is');
// Check for <super-button> and <button is="super-button">.
return el.localName.includes('-') || isAttr && isAttr.includes('-');
}
function findAllCustomElements(nodes) {
for (let i = 0, el; el = nodes[i]; ++i) {
if (isCustomElement(el)) {
allCustomElements.push(el);
}
// If the element has shadow DOM, dig deeper.
if (el.shadowRoot) {
findAllCustomElements(el.shadowRoot.querySelectorAll('*'));
}
}
}
findAllCustomElements(document.querySelectorAll('*'));
<template> şablonundan öğe oluşturma
Bir gölge kökünü .innerHTML
kullanarak doldurmak yerine bildirim tabanlı kullanabiliriz
<template>
. Şablonlar, projenin yapısını açıklamak için ideal bir yer tutucudur
bir web bileşenidir.
Aşağıdaki örnekte "Özel öğeler: Yeniden kullanılabilir web bileşenleri oluşturma".
Tarih ve tarayıcı desteği
Son birkaç yıldır web bileşenlerini takip ediyorsanız
Chrome 35 ve sonraki sürümlerin/Opera'nın Windows 1.0 sürümü için gölge DOM'nin eski bir sürümünü gönderdiğini
biraz zaman alabilir. Blink, bazı uygulamalar için her iki sürümü de paralel olarak desteklemeye devam edecektir.
gerekir. v0 spesifikasyonu, gölge kökü oluşturmak için farklı bir yöntem sağladı
(v1'in element.attachShadow
yerine element.createShadowRoot
).
eski yöntem, v0 semantiğiyle bir gölge kökü oluşturmaya devam ediyor. Dolayısıyla, mevcut v0
zaman harcıyor.
Eski v0 spesifikasyonuyla ilgileniyorsanız html5rocks'a göz atın. makaleler: 1, 2, 3. Ayrıca, burada görmeye alışkın olduğumuz gölge DOM v0 ile v1 arasındaki farklar hakkında daha fazla bilgi edinin.
Tarayıcı desteği
Gölge DOM v1, Chrome 53'te (durum) gönderilir Opera 40, Safari 10 ve Firefox 63. Kenar geliştirmeye başladı.
Gölge DOM'u özellik algılamak için attachShadow
olup olmadığını kontrol edin:
const supportsShadowDOMV1 = !!HTMLElement.prototype.attachShadow;
Çoklu Dolgu
Tarayıcı desteği yaygın olarak kullanıma sunulana kadar shadydom ve shadycss polyfill'leri size v1'i verir özelliğini kullanabilirsiniz. Gölgeli DOM, Gölge DOM ve shadycss polyfill'lerinin DOM kapsamını taklit eder CSS özel özellikleri ve yerel API'nin sağladığı stil kapsamı.
Polyfill'leri takın:
bower install --save webcomponents/shadydom
bower install --save webcomponents/shadycss
Çoklu dolguları kullanın:
function loadScript(src) {
return new Promise(function(resolve, reject) {
const script = document.createElement('script');
script.async = true;
script.src = src;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
// Lazy load the polyfill if necessary.
if (!supportsShadowDOMV1) {
loadScript('/bower_components/shadydom/shadydom.min.js')
.then(e => loadScript('/bower_components/shadycss/shadycss.min.js'))
.then(e => {
// Polyfills loaded.
});
} else {
// Native shadow dom v1 support. Go to go!
}
https://github.com/webcomponents/shadycss#usage adresine göz atın inceleyin.
Sonuç
İlk kez, doğru CSS kapsamı oluşturan bir API temel bileşenimiz var,
DOM kapsamı ve gerçek bir bileşimi vardır. Diğer web bileşeni API'leriyle birleştirildi
gibi gölge DOM'yi de kullanabilirsiniz. Gölge DOM,
veya <iframe>
gibi daha eski bagajlar
kullanan eski bagajlar olabilir.
Yanlış anlamayın. Gölge DOM gerçekten karmaşık bir canavar. Ama canavar öğrenmeye değer. Biraz vakit geçirin. Öğrenin ve soru sorun!
Daha fazla bilgi
- Gölge DOM v1 ile v0 arasındaki farklar
- "Slot Tabanlı Gölge DOM API'siyle Tanışın" bulabilirsiniz.
- Web Bileşenleri ve Modüler CSS'nin geleceği Hazırlayan: Philip Walton
- "Özel öğeler: Yeniden kullanılabilir web bileşenleri oluşturma" Google'ın WebFundamentals programından.
- Shadow DOM v1 spesifikasyonu
- Özel öğeler v1 spesifikasyonu
SSS
Gölge DOM v1'i bugün kullanabilir miyim?
Çoklu dolgu ile evet. Tarayıcı desteği sayfasına göz atın.
Gölge DOM hangi güvenlik özelliklerini sağlar?
Gölge DOM bir güvenlik özelliği değildir. CSS'nin kapsamını belirlemek için kullanılan hafif bir araçtır
ve DOM ağaçlarını bileşende gizlemeyi deneyin. Gerçek bir güvenlik sınırı istiyorsanız
<iframe>
kullanın.
Bir web bileşeninin gölge DOM'yi kullanması gerekiyor mu?
Hayır. Gölge DOM kullanan web bileşenleri oluşturmanız gerekmez. Ancak, Gölge DOM kullanan özel öğeler yazmak, ve kompozisyon (ör. CSS kapsamı, DOM kapsülleme) ve
Açık ve kapalı gölge kökleri arasındaki fark nedir?
Kapalı gölge kökleri konusuna bakın.