初识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. java学习之观察者设计模式

    package com.gh.observer; import java.util.Observable; /** * 被观察者对象 * 必须继承被观察者抽象类 * @author ganhang * ...

  2. Objective-C 类,实例成员,静态变量,对象方法,类方法(静态方法),对象,

    Objective-C 类,实例成员,静态变量,对象方法,类方法(静态方法),对象, 一.类 在ios中,类的声明和实现时分离的,也就是说不能写在同一个文件中,声明放在 .h文件中,实现放在 .m 文 ...

  3. struts2的总体回想(ACTION、拦截器、值栈、OGNL表达式、ModelDriven方案等)

    ValueStack:struts2的一个存放数据的数据结构(核心) ValueStack大致能够理解为:由Map和对象栈组成 ValueStack作用范围:一个请求,用它来取代request的作用域 ...

  4. caffe神经网络框架的辅助工具(将图片转换为leveldb格式)

    caffe中负责整个网络输入的datalayer是从leveldb里读取数据的,是一个google实现的很高效的kv数据库. 因此我们训练网络必须先把数据转成leveldb的格式. 这里我实现的是把一 ...

  5. CKEditor和CKFinder整合实现上传下载功能

    CKEditor与CKFinder整合并实现文件上传功能 事先说明:此整合的是java版本号的, 用到的有:jsp + ckeditor + ckfinder (没有servlet 及其他框架技术) ...

  6. OpenStack里对VPN的支持

    今天翻自己的笔记找到了点去年研究Cloudpipe的东西: 对于用VLAN隔开的项目内主机的访问,可以使用CloudPipe来进行VPN访问 其实就是把OpenStack和OpenVPN集成了一下,给 ...

  7. gcc支持c99验证

    gcc3.0以上的版本都是支持C99标准的, 但是编译程序的时候需要加上    -std=c9  才可以: 一下程序是验证gcc是否支持c99标准的: #include <stdio.h> ...

  8. Python基础2:反射、装饰器、JSON,接口

    一.反射 最近接触到python的反射机制,遂记录下来已巩固.但是,笔者也是粗略的使用了__import__, getattr()函数而已.目前,笔者的理解是,反射可以使用户通过自定义输入来导入响应的 ...

  9. JQuery中两个ul标签的li互相移动实现方法

    这篇文章主要介绍了JQuery中两个ul标签的li互相移动实现方法,可实现ul标签中li标签内容相互替换的技巧,涉及jQuery操作页面元素的相关技巧,需要的朋友可以参考下 本文实例讲述了JQuery ...

  10. 设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型)

      设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型) 1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的 ...