shadow dom
初识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的更多相关文章
- 【shadow dom入UI】web components思想如何应用于实际项目
回顾 经过昨天的优化处理([前端优化之拆分CSS]前端三剑客的分分合合),我们在UI一块做了几个关键动作: ① CSS入UI ② CSS作为组件的一个节点而存在,并且会被“格式化”,即选择器带id前缀 ...
- 封印术:shadow dom
置顶文章:<纯CSS打造银色MacBook Air(完整版)> 上一篇:<鼠标滚动插件smoovejs和wowjs> 作者主页:myvin 博主QQ:851399101(点击Q ...
- 使用shadow dom封装web组件
什么是shadow dom? 首先我们先来看看它长什么样子.在HTML5中,我们只用写如下简单的两行代码,就可以通过 <video> 标签来创建一个浏览器自带的视频播放器控件. <v ...
- shadow dom 隔离代码 封装
Shadow DOM是指浏览器的一种能力,它允许在文档(document)渲染时插入一棵DOM元素子树,但是这棵子树不在主DOM树中. Shadow DOM 解决了 DOM 树的封装问题. ...
- 纯CSS菜单样式,及其Shadow DOM,Json接口 实现
先声明,要看懂这篇博客要求你具备少量基础CSS知识, 当然如果你只是要用的话就随便了,不用了解任何知识 完整项目github链接:https://github.com/git-Code-Shelf/M ...
- JavaScript 是如何工作:Shadow DOM 的内部结构 + 如何编写独立的组件!
这是专门探索 JavaScript 及其所构建的组件的系列文章的第 17 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...
- Shadow DOM及自定义标签
参考链接:点我 一.什么是Shadow DOM Shadow DOM,直接翻译的话就是 影子 DOM,可以理解为潜藏在 DOM 结构中并且我们无法直接控制操纵的 DOM 结构.类似于下面这种结构 Sh ...
- 理解Shadow DOM(一)
1. 什么是Shadow DOM? Shadow DOM 如果按照英文翻译的话可以理解为 影子DOM, 何为影子DOM呢?可以理解为一般情况下使用肉眼看不到的DOM结构,那如果一般情况下看不到的话,那 ...
- html 中shadow DOM 的使用
什么是shadow DOM? An important aspect of web components is encapsulation — being able to keep the marku ...
随机推荐
- java学习之观察者设计模式
package com.gh.observer; import java.util.Observable; /** * 被观察者对象 * 必须继承被观察者抽象类 * @author ganhang * ...
- Objective-C 类,实例成员,静态变量,对象方法,类方法(静态方法),对象,
Objective-C 类,实例成员,静态变量,对象方法,类方法(静态方法),对象, 一.类 在ios中,类的声明和实现时分离的,也就是说不能写在同一个文件中,声明放在 .h文件中,实现放在 .m 文 ...
- struts2的总体回想(ACTION、拦截器、值栈、OGNL表达式、ModelDriven方案等)
ValueStack:struts2的一个存放数据的数据结构(核心) ValueStack大致能够理解为:由Map和对象栈组成 ValueStack作用范围:一个请求,用它来取代request的作用域 ...
- caffe神经网络框架的辅助工具(将图片转换为leveldb格式)
caffe中负责整个网络输入的datalayer是从leveldb里读取数据的,是一个google实现的很高效的kv数据库. 因此我们训练网络必须先把数据转成leveldb的格式. 这里我实现的是把一 ...
- CKEditor和CKFinder整合实现上传下载功能
CKEditor与CKFinder整合并实现文件上传功能 事先说明:此整合的是java版本号的, 用到的有:jsp + ckeditor + ckfinder (没有servlet 及其他框架技术) ...
- OpenStack里对VPN的支持
今天翻自己的笔记找到了点去年研究Cloudpipe的东西: 对于用VLAN隔开的项目内主机的访问,可以使用CloudPipe来进行VPN访问 其实就是把OpenStack和OpenVPN集成了一下,给 ...
- gcc支持c99验证
gcc3.0以上的版本都是支持C99标准的, 但是编译程序的时候需要加上 -std=c9 才可以: 一下程序是验证gcc是否支持c99标准的: #include <stdio.h> ...
- Python基础2:反射、装饰器、JSON,接口
一.反射 最近接触到python的反射机制,遂记录下来已巩固.但是,笔者也是粗略的使用了__import__, getattr()函数而已.目前,笔者的理解是,反射可以使用户通过自定义输入来导入响应的 ...
- JQuery中两个ul标签的li互相移动实现方法
这篇文章主要介绍了JQuery中两个ul标签的li互相移动实现方法,可实现ul标签中li标签内容相互替换的技巧,涉及jQuery操作页面元素的相关技巧,需要的朋友可以参考下 本文实例讲述了JQuery ...
- 设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型)
设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型) 1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的 ...