初识shadow dom

我们先看个input="range"的表现:

what amazing ! 一个dom能表现出这么多样式嘛?

无论是初学者和老鸟都是不肯相信的,于是在好奇心的驱使下,我们打开chrome的开发工具设置

结果发现了input节点里面有我们需要的答案

input节点里面有他表现需要的dom节点,dom节点里面还有些样式,而这些不容易为人知的节点都在一个#shadow-root的节点下面。

来张图了解下结构

document

这个很好理解,就是我们的正常文档 document 。

shadow host

对于一个内部有 shadow-dom 的元素而言,它必然需要一个宿主元素,对于上面的例子而言, <input> 标签,就是 shadow-dom 的宿主元素。

shadow-root

通过 createShadowRoot(下文会提及) 返回的文档片段被称为 shadow-root 。它和它的后代元素,都将对用户隐藏,但是它们是实际存在的,在 chrome 中,我们可以通常审查元素去查看它们的具体 DOM 实现。

在 此例子的 input 中,例如滑块,滑块条等都是 shadow-root 的后代。它们工作时会显示在屏幕上,但他们的 DOM 结构对用户是不可见的。

contents

就是上述所说的 input 中各子组件的 DOM 的具体实现。

shadow dom的api

下文先从例子出发学习api,再由API了解shadow dom的特性,不失为学习的好方法

helloWord:

 <div class="widget"></div>
<script>
var host = document.querySelector('.widget');
var root = host.createShadowRoot();
root.textContent = 'hello world!';
</script>

页面的效果是

dom结构也和想象中一样:在div.widget>shadow-root>text(hello world)

shadowHost.createShadowRoot:在shadowHost内创建ShadowRoot节点
dom操作
再来个简单的例子
<body>
<div class="widget">Hello, world!</div>3 <script>
var host = document.querySelector('.widget');
var root = host.createShadowRoot(); var header = document.createElement('h1');
header.textContent = '影子标题'; var paragraph = document.createElement('p');
paragraph.textContent = '影子文本'; root.appendChild(header);
root.appendChild(paragraph);
</script>
</body>

效果和dom结构也和想象中一样,只是div.widget(shadowHost)内的内容不见了,没错,在有shadowDom的情况下ShadowHost内的真实节点并不会渲染。

从这个例子发现普通的dom操作在shadowDom也是可行的

template/content

在之前的例子里,我们用shadow root里面的内容完全替换掉了shdow host里面的内容。但这种奇技淫巧在实际开发中没什么用。真正有用的是我们可以从shdow host中获取内容,并使用shdow root中的结构将这些内容呈现。

<body>
<div class="widget">
ShadowRootText
</div> <template class="template">
<h1>ShadowRoot的内容出现了 <content>ShadowRootText</content> 出现了!</h1>
</template> <script>
var host = document.querySelector('.widget');
var root = host.createShadowRoot();
var template = document.querySelector('.template');
root.appendChild(document.importNode(template.content, true));
</script>
</body>

效果如下

dom结构也是想象中的那样:shadow host里面的内容都插进了shadow root的content节点里面了

使用 <content> 标签,我们创建了一个insertion point(<content>),其将 div.pokemon 中的文本projects 出来,使之得以在我们的影子节点 <h1> 中展示。

插入点十分强大,它允许我们在不改变源代码的情况下改变渲染顺序,这也意味着我们可以对要呈现的内容进行选择。

select 属性

<body>
<div class="widget">
<span class="contury">中国</span>
<span class="city">广州</span>
<span class="province">广东</span>
<p>广州好很塞车</p>
</div> <template class="template">
<dl>
<dt>国家</dt>
<dd><content select=".contury"></content></dd>
<dt>省份</dt>
<dd><content select=".province"></content></dd>
<dt>城市</dt>
<dd><content select=".city"></content></dd>
</dl>
<p><content select=""></content></p>
</template> <script>
var host = document.querySelector('.widget');
var root = host.createShadowRoot();
var template = document.querySelector('.template');
root.appendChild(template.content);
</script>
</body>

页面效果

dom结构

在这个例子中,content里面能选择shadow root里面的insertion point能通过select属性选择出shadow host里面的内容,

并且,页面显示顺序是按照shadow root里面的template顺序显示,并不会按照shadow host的数据显示顺序显示,由此可发现

shadow root 负责渲染的结构、顺序,shadow host负责渲染的数据(接触过angularJS的directive的你是否看完后是否会微微一笑)

贪心插入点

<body>
<div class="widget">
<p>shadow host text</p>
</div> <template class="template"> <p><content ></content>
<p><content select=""></content>
<p><content select="*"></content> </template> <script>
var host = document.querySelector('.widget');
var root = host.createShadowRoot();
var template = document.querySelector('.template');
root.appendChild(template.content);
</script>
</body>

template有三个content,三个content都是匹配shadow host的内容的,那么显示的效果是三行文本还是一行呢?

结果显示是这样的

dom结构是这样的

这是因为这个选择器是贪心的,而且元素只能被选择一次。我们一旦把贪心选择器匹配了shadow host的内容,他就会将所有内容都抓取,不给其他 select 选择器留一点内容。

样式封装

shadow DOM 有着独立的样式作用域(shadow boundary),shadow boundary的主要好处就是防止主 DOM 中的样式泄露到 shadow DOM 中。

这就意味着即使你在主文档中有一个针对全部标签的样式选择器,这个样式也不会不经你的允许便影响到 shadow DOM 的元素。

来个例子:

<body>
<style>
p {
font:18/1.5 SimSum;
}
</style>
<p>this is normal text</p>
<div></div> <script>
var host = document.querySelector('div');
var root = host.createShadowRoot();
root.innerHTML = '<style>p { font:bold 30px/60px "microsoft yahei";color:red } </style>' +
'<p>this is shadow text</p>'
</script>
</body>

显示的效果是这样的

normal text的样式并不会对shadow text产生影响,一个困扰前端届多年的独立CSS作用域就这么实现了。

Amazing,不用担心改这个按钮的样式也会影响到其他页面的按钮了,赞~

宿主样式(:host)

我经常把shadow host想象成一栋建筑物的外表。这栋建筑物的内部有组件的全部运行方式,外面有一个好的门面。 许多情况下你可能会想给这门面调整一下样式,这就轮到 :host 选择器出场了。

<body>
<style>
.widget {
text-align: center;
}
</style> <div class="widget">
<p>Hello World!</p>
</div> <script>
var host = document.querySelector('.widget');
var root = host.createShadowRoot();
root.innerHTML = '<style>' +
':host {' +
' border: 2px dashed red;' +
' text-align: left;' +
' font-size: 28px;' +
'} ' +
'</style>' +
'<content></content>';
</script>
</body>

显示的效果是下图

文字28px,还有个小边框,文字是居中对齐的,并没有按照shadow root里面



shadow dom的更多相关文章

  1. 【shadow dom入UI】web components思想如何应用于实际项目

    回顾 经过昨天的优化处理([前端优化之拆分CSS]前端三剑客的分分合合),我们在UI一块做了几个关键动作: ① CSS入UI ② CSS作为组件的一个节点而存在,并且会被“格式化”,即选择器带id前缀 ...

  2. 封印术:shadow dom

    置顶文章:<纯CSS打造银色MacBook Air(完整版)> 上一篇:<鼠标滚动插件smoovejs和wowjs> 作者主页:myvin 博主QQ:851399101(点击Q ...

  3. 使用shadow dom封装web组件

    什么是shadow dom? 首先我们先来看看它长什么样子.在HTML5中,我们只用写如下简单的两行代码,就可以通过 <video> 标签来创建一个浏览器自带的视频播放器控件. <v ...

  4. shadow dom 隔离代码 封装

    Shadow DOM是指浏览器的一种能力,它允许在文档(document)渲染时插入一棵DOM元素子树,但是这棵子树不在主DOM树中.   Shadow DOM 解决了 DOM 树的封装问题.     ...

  5. 纯CSS菜单样式,及其Shadow DOM,Json接口 实现

    先声明,要看懂这篇博客要求你具备少量基础CSS知识, 当然如果你只是要用的话就随便了,不用了解任何知识 完整项目github链接:https://github.com/git-Code-Shelf/M ...

  6. JavaScript 是如何工作:Shadow DOM 的内部结构 + 如何编写独立的组件!

    这是专门探索 JavaScript 及其所构建的组件的系列文章的第 17 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...

  7. Shadow DOM及自定义标签

    参考链接:点我 一.什么是Shadow DOM Shadow DOM,直接翻译的话就是 影子 DOM,可以理解为潜藏在 DOM 结构中并且我们无法直接控制操纵的 DOM 结构.类似于下面这种结构 Sh ...

  8. 理解Shadow DOM(一)

    1. 什么是Shadow DOM? Shadow DOM 如果按照英文翻译的话可以理解为 影子DOM, 何为影子DOM呢?可以理解为一般情况下使用肉眼看不到的DOM结构,那如果一般情况下看不到的话,那 ...

  9. html 中shadow DOM 的使用

    什么是shadow DOM? An important aspect of web components is encapsulation — being able to keep the marku ...

随机推荐

  1. 【JUnit4.10源码分析】5 Statement

    假设要评选JUnit中最最重要的类型.或者说核心,无疑是org.junit.runners.model.Statement.Runner等类型看起来热闹而已. package org.junit.ru ...

  2. N皇后( DFS,推荐)

    N皇后问题 Description   在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上.          你的任 ...

  3. 关于PHPExcel类占用内存问题

    最近在帮一家公司做后台excel导出功能,使用的工具类是phpexcel,因为这个类功能比较强大.全面. 但是遇到下面一个问题: 当导出数据量达到一定数量级的时候,比如说1000条,服务器出现卡顿.白 ...

  4. C语言深度剖析--volatile(转载)

    volatile关键字和const一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统,硬件或者其他线程等等.遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进 ...

  5. jq商品展示图放大镜 and 原生js和html5写的放大镜效果 ~~效果不错

    <!DOCTYPE HTML><html lang="en-US"><head> <meta charset="UTF-8&qu ...

  6. redis(二)redis+TCMALLOC高性能的缓存服务器的安装配置

    安装  1准备编译环境    yum -y install gcc gcc+ gcc-c++ openssl openssl-devel pcre pcre-devel  2 下载源码包(由于goog ...

  7. 批量的单向的ssh 认证

    <pre name="code" class="python">if [ ! $# -eq 2 ] ;then echo "请输入用户密码 ...

  8. 基于visual Studio2013解决C语言竞赛题之0605strcat

      题目

  9. linux BC命令行计算器

    1. 基本使用: $ bc <<< 5*4 20 $ bc <<< 5+4 9 $ bc <<< 5-4 1 或者 $ echo "5* ...

  10. Android - Mac系统Android程序位置

    Mac系统Android程序位置 本文地址: http://blog.csdn.net/caroline_wendy Mac系统是类Unix系统.Android程序直接安装至目录.能够使用" ...