shadow dom & web components(2)

- 1 min

这里主要补充一下上一篇日志没有讲到的地方。

###使用多个root

在某些情景下,我们可能会将多个shadow dom treeroot挂载到同一个host上,这时就会出现问题:

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

image

这段代码只输出了root2,并没有输出root1,这是因为整个shadow dom的显示,可以看做是一个,也就是有后进先出的原则,在这里的体现就是只显示最后被创建的shadow dom tree

root间的这种先后关系,我们可以通过olderShadowRoot来获取

root2.olderShadowRoot === root1; // true

那么是不是就没有办法实现将多个shadow dom tree挂载到同一个host上了呢?

当然不是,我们可以通过使用<shadow>作为占位符,使一个host上可以挂载多个shadow dom

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

image

通过在root2的内容中添加<shadow>占位符,我们实现了将root1也挂载到host下。显示上顺序是root2root1上面,这是因为我们的<shandow>占位符的位置决定的,如果将<shadow>换个位置,就会看到显示顺序改变了。

如果一段内容中有多个<shadow>占位符,那么将只有个第一个占位符起作用,其他的全都无效。

###插入点(insertion points)

上一篇博客说了如何通过<content>创建一个可容纳信息的容器,这种容器又被称作insertion points,这个过程也被称为distribute。通过distribute过程,我们可以将对应的内容放到正确的位置上,但是在shadow dom treeroot上,是无法获取到<content>节点的。

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

虽然我们没有办法获取<content>中的内容,但是我们可以使用getDistributedNodes方法拿到被distribute的元素。

<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"></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');
	});
	console.log(html.join(''));
	/*
	<content select="h2"></content>: <h2>Eric</h2><h2>Bidelman</h2>
	<content select="div"></content>: <div>Digital Jedi</div>
	<content select="h4"></content>: <h4>footer text</h4>
	*/
</script>

通过输出的结果,可以看到el.getDistributedNodes方法取到的正是被distribute的元素。

通过getDistributedNodes我们可以在root中拿到<content>内部的元素,与之类似,我们还可以通过getDestinationInsertionPoints来获取insertion points的信息:

<div id="host">
	<h2>Light DOM</h2>
</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);
 	});
 	
 	/*
 	<content select=​"h2">​</content>​
	<shadow>​</shadow>​
 	*/
</script>

###事件模型

rss facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora