İleri düzey kavramlar ve DOM API'leri
Bu makalede, Gölge DOM ile yapabileceğiniz diğer şaşırtıcı işlemler hakkında daha fazla bilgi verilmektedir. Bu makale, Gölge DOM 101 ve Gölge DOM 201'de ele alınan kavramları temel alır.
Birden fazla gölge kökü kullanma
Parti veriyorsanız herkesin aynı odada sıkışması can sıkıcı olabilir. Kullanıcı gruplarını birden fazla odaya dağıtma seçeneğiniz olsun istiyorsunuz. Gölge DOM barındıran öğeler de bunu yapabilir, yani aynı anda birden fazla gölge kökü barındırabilir.
Bir ana makineye birden fazla gölge kök eklemeye çalışırsak ne olur?
<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>
Daha önce bir gölge ağacı eklemiş olsak da sonuç olarak "Kök 2 FTW" oluşturulur. Bunun nedeni, bir ana makineye eklenen son gölge ağacının kazanmasıdır. Bu, oluşturma söz konusu olduğunda bir LIFO yığınıdır. Geliştirici Araçları'nı inceleyerek bu davranışı doğrulayabilirsiniz.
Peki, oluşturma işlemine yalnızca son gölge davet ediliyorsa birden fazla gölge kullanmanın ne anlamı var? Gölge ekleme noktalarını girin.
Gölge kampanya siparişi giriş noktaları
"Gölge kampanya ekleme noktaları" (<shadow>
), yer tutucu olmaları açısından normal kampanya ekleme noktalarına (<content>
) benzer. Ancak bu düğümler, barındırıcının içeriği için yer tutucu olmak yerine diğer gölge ağaçları için barındırıcı görevi görür.
Gölge DOM'u kullanmaya başlıyoruz.
Tahmin edebileceğiniz gibi, konuyu ne kadar ayrıntılı bir şekilde incelerseniz o kadar karmaşık bir hal alır. Bu nedenle, birden fazla <shadow>
öğesi oyunda olduğunda ne olacağı konusunda spesifikasyon çok nettir:
İlk örneğimize dönersek ilk gölge root1
davet listesinden çıkarılmıştır. <shadow>
ekleme noktası ekleyerek şunu elde edebilirsiniz:
<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>
Bu örnekle ilgili birkaç ilginç nokta var:
- "Root 2 FTW", "Root 1 FTW" ifadesinin üzerinde gösterilmeye devam eder. Bunun nedeni,
<shadow>
ekleme noktasını yerleştirdiğimiz yerdir. Tersini yapmak istiyorsanız ekleme noktasını taşıyın:root2.innerHTML = '<shadow></shadow><div>Root 2 FTW</div>';
. - Artık root1'de
<content>
ekleme noktası olduğuna dikkat edin. Bu, oluşturma işlemi için "Light DOM" metin düğümünü gösterir.
<shadow>
adresinde ne oluşturulur?
Bazen eski gölge ağacının <shadow>
olarak oluşturulduğunu bilmek yararlı olabilir. .olderShadowRoot
üzerinden bu ağaç için referans alabilirsiniz:
**root2.olderShadowRoot** === root1 //true
Ana makinenin gölge kökünü alma
Bir öğe Gölge DOM barındırıyorsa .shadowRoot
kullanarak en genç gölge köküne erişebilirsiniz:
var root = host.createShadowRoot();
console.log(host.shadowRoot === root); // true
console.log(document.body.shadowRoot); // null
Kullanıcıların gölgelerinizin içine girmesinden endişeleniyorsanız .shadowRoot
değerini null olarak yeniden tanımlayın:
Object.defineProperty(host, 'shadowRoot', {
get: function() { return null; },
set: function(value) { }
});
Bu biraz hile gibi görünse de işe yarıyor. Son olarak, Shadow DOM'un güvenlik özelliği olarak tasarlanmadığını unutmayın. İçeriklerin tamamen izole edilmesi için bu yönteme güvenmeyin.
JS'de gölge DOM oluşturma
DOM'u JS'de oluşturmayı tercih ediyorsanız HTMLContentElement
ve HTMLShadowElement
için uygun arayüzler vardır.
<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>
Bu örnek, önceki bölümdeki örneğe neredeyse aynıdır.
Tek fark, yeni eklenen <span>
öğesini almak için artık select
kullanacağım.
Ekleme noktalarıyla çalışma
Ana makine öğesinden seçilen ve gölge ağaca "dağıtılan" düğümlere…davul sesi…dağıtılmış düğümler denir. Ekleme noktaları onları davet ettiğinde gölge sınırını geçmelerine izin verilir.
Ekle noktalarının kavramsal olarak tuhaf olan yanı, DOM'u fiziksel olarak hareket ettirmemeleridir. Ana makinenin düğümleri bozulmadan kalır. Ekleme noktaları, ana makinedeki düğümleri gölge ağaca yeniden yansıtır. Bu, sunum/oluşturmayla ilgili bir şey: "Bu düğümleri buraya taşıyın" "Bu düğümleri bu konumda oluşturun."
Örneğin:
<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>
Ve işte! h2
, gölge DOM'un alt öğesi değildir. Bu da başka bir ipucu doğuruyor:
Element.getDistributedNodes()
<content>
içinde gezinemeyiz ancak .getDistributedNodes()
API'si, dağıtılmış düğümleri bir ekleme noktasında sorgulamamıza olanak tanır:
<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()
'a benzer şekilde, .getDestinationInsertionPoints()
adını çağırarak bir düğümün hangi ekleme noktalarına dağıtıldığını kontrol edebilirsiniz:
<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>
Araç: Shadow DOM Görselleştirici
Gölge DOM'un kara büyüsünü anlamak zordur. İlk kez bu konuyu anlamaya çalıştığımı hatırlıyorum.
Shadow DOM oluşturmanın nasıl çalıştığını görselleştirmenize yardımcı olmak için d3.js'yi kullanarak bir araç oluşturdum. Sol taraftaki her iki işaretleme kutusu da düzenlenebilir. Kendi işaretlemenizi yapıştırıp nasıl çalıştığını ve ekleme noktalarının ana düğümleri gölge ağacında nasıl değiştirdiğini görmek için denemeler yapabilirsiniz.
Deneyin ve ne düşündüğünüzü bana bildirin.
Etkinlik Modeli
Bazı etkinlikler gölge sınırını geçer, bazıları ise geçmez. Etkinliklerin sınırı aştığı durumlarda, etkinlik hedefi, gölge kökün üst sınırının sağladığı kapsüllemeyi korumak için ayarlanır. Yani etkinlikler, gölge DOM'daki dahili öğeler yerine ana öğeden gelmiş gibi görünecek şekilde yeniden hedeflenir.
Play Action 1
- Bu ilginç bir konu. Barındırma öğesinden (
<div data-host>
) mavi düğüme birmouseout
göreceksiniz. Dağıtılmış bir düğüm olsa da ShadowDOM'da değil, ana makinede bulunur. Fareyle daha aşağıya, sarıya doğru gittiğinizde mavi düğümdemouseout
simgesi görünür.
İşlemi 2'yi oynat
- Ana makinede (en sonunda) bir
mouseout
görünür. Normalde, tüm sarı bloklar içinmouseout
etkinliğinin tetiklendiğini görürsünüz. Ancak bu durumda bu öğeler Gölge DOM'un içindedir ve etkinlik üst sınırından taşmaz.
Action 3'ü oynama
- Girişi tıkladığınızda
focusin
simgesinin girişte değil, ana makine düğümünde göründüğünü unutmayın. Reklam yeniden hedeflendi.
Her zaman durdurulan etkinlikler
Aşağıdaki etkinlikler hiçbir zaman gölge sınırını aşmaz:
- bırak yapma
- hata
- seç
- değiştir
- load
- reset
- resize
- scroll
- selectstart
Sonuç
Gölge DOM'un inanılmaz derecede güçlü olduğunu kabul edeceğinizi umuyoruz. İlk kez, <iframe>
veya diğer eski tekniklerin ek yükünü taşımadan uygun bir kapsülleme elde ettik.
Gölge DOM kesinlikle karmaşık bir canavardır ancak web platformuna eklenmeye değer bir canavardır. Bu cihazla biraz zaman geçirin. Öğrenin. Soru sorun.
Daha fazla bilgi edinmek için Dominic'in Shadow DOM 101 başlıklı giriş makalesine ve Shadow DOM 201: CSS & Styling başlıklı makaleme göz atın.