Gölge DOM 301

İleri düzey kavramlar ve DOM API'leri

Bu makalede, Shadow DOM ile yapabileceğiniz diğer şaşırtıcı işlemler hakkında daha fazla bilgi verilmektedir. Bu eğitim, 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. Shadow DOM barındıran öğeler de bunu yapabilir. Yani aynı anda birden fazla Shadow kökü barındırabilirler.

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ş olmamıza rağmen "Root 2 FTW" olarak oluşturulur. Bunun nedeni, bir ana makineye eklenen son gölge ağacının kazanmasıdır. Oluşturma işlemi söz konusu olduğunda bu 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 kullanıldığında ne olacağıyla ilgili olarak spesifikasyonda net bir açıklama yer alır:

İlk örneğimize dönersek ilk gölge root1 davet listesinden çıkarılmıştır. <shadow> ekleme noktası ekleyerek bu özelliği geri getirebilirsiniz:

<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 örnekte ilginç olan birkaç nokta vardır:

  1. "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>';.
  2. root1 içinde artık bir <content> ekleme noktası olduğunu fark edin. Bu sayede, "Light DOM" metin düğümü oluşturma işlemine dahil edilir.

<shadow> adresinde ne oluşturulur?

Bazen eski gölge ağacının <shadow> olarak oluşturulduğunu bilmek yararlı olabilir. .olderShadowRoot aracılığıyla bu ağaca 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 bilgiye işaret eder:

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()'e benzer şekilde, bir düğümün .getDestinationInsertionPoints() değerini çağırarak 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.

Gölge DOM Görselleştirici
Gölge DOM Görüntüleyici'yi başlatın

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 bir mouseout 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üğümde mouseout simgesi görünür.

Play Action 2

  • Ana makinede (en sonunda) bir mouseout görünür. Normalde, tüm sarı bloklar için mouseout 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>'ler 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.