Gölge DOM 301

İ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:

  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. 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.

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.

İşlemi 2'yi oynat

  • 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> 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.