浅谈 shadow dom 中的 template 和 slot

最近一个内部系统可视化设计器的布局在用户升级 chrome 到 53 版本之后,里面的坑位增加按钮消失了,经过排查发现,坑位的标签使用了slot,而坑位中的按钮是通过 css 的 empty 伪类实现的,即坑位为空时,出现增加按钮,但现在为什么突然无效了呢?

slot的名字换成其他标签名,发现样式顿时生效,于是猜测是slot作为特殊标签被 chrome 设置了特定的行为,经过查阅资料发现slotshadow dom 中的内置标签。

现在我们来了解下 shadow dom 以及与其相关的两个特殊标签 templateslot

何为shadow dom

shadow dom,顾名思义,影子节点,它是 web components 规范的一个子集,主要为了解决dom对象的封装,通常的dom,其js行为和css样式极易受到别的代码的干扰,但shadow dom规定了只有其宿主才可定义其表现,外部的api是无法获取到shadow dom中的东西。

由于shadow dom是影子元素,因此其必须捆绑一个宿主元素,宿主元素事实上成为了“傀儡”,宿主元素的内容将被隐藏,而shadow dom的内容将展示出来,以下是一个例子:

html:
<div id="con">
    没什么卵用的文字
</div>

js:
var host = document.querySelector('#con');
var root = host.attachShadow({mode:'open'});//为宿主附加一个影子元素

root.innerHTML = "我来自shadow dom";//为影响元素附上内容,shadow dom的api和普通dom的大致相同

最终效果:

我来自shadow dom

可以看到,宿主的内容确实被掩盖了,然而通过chrome的devtools,可以看到宿主的原内容以及背后的shadow dom:

shadow dom中的template

前面说了,shadow dom可以实现dom的隔离,比如样式的封装,那么如何实现呢?shadow规定了一种名为template的标签,这种标签类似我们经常用的<script type='tpl'>,它不会被解析为dom树的一部分,template的内容可以被塞入到shadow dom中并且反复利用,在template中可以设置style,但只对这个template中的元素有效,看下示例:

html:
<style>
span {
  background-color:blue;/*设置页面所有span背景为蓝色,然而对shadow dom没什么卵用*/
}
</style>
<div id="con">
    没什么卵用的文字
  </div>
   <template id="tpl">
     <style>
       span {
         color:red;
       }
     </style>
     <span>hello world</span>
   </template>

js:
var host = document.querySelector('#con');
var root = host.attachShadow({mode:'open'});

var con = document.getElementById("tpl").content.cloneNode(true);

root.appendChild(con);

效果截图:

<span style='color:red'>hello world</span>

可以看到,template的内容被塞入到宿主,并且其文案被设置为红色,而body 中对 span 设置为蓝色背景却没有生效;另外这里要注意document.getElementById("tpl").content中的content属性,它是template标签的特有属性,你可以通过嗅探该属性来判断浏览器是否支持shadow dom和template标签。

shadow dom的slot标签

由于shadow dom的内容会掩盖宿主的内容,那么现在问题来了,我就是想把宿主的内容显示出来怎么办?

最新的shadow dom草案支持了一个叫slot标签的东西,slot是一个插槽,一个坑位,可以在template中定义坑位,然后宿主中的内容可以标记属于哪一个坑位,这样一个萝卜一个坑,宿主的内容就会被正确地插入到template所标记的位置去,还是来看一个例子:

html:
<div id="con">
    没什么卵用的文字
    <span slot="main1">
      坑位1
    </span>
    <span slot="main2">
      坑位2
    </span>
    没什么卵用的文字 </div>
  <template id="tpl">tpl begin
    <slot name="main1">
    </slot>
    <slot name="main2">
    </slot>
    tpl end
      </template>

js:
var host = document.querySelector('#con');
var root = host.attachShadow({mode:'open'});

var con = document.getElementById("tpl").content.cloneNode(true);

root.appendChild(con);

最终的效果是:

tpl begin 坑位1 坑位2 tpl end

可以看到,宿主中的两个span分别插入到了其标记的slot坑位中。在slot出现之前,仍然可以实现类似的功能,只不过标签名叫content

结语

现在我们来解释一下文章开头出现的问题的原因,由于 slot标签仅仅是一个占位符而已,其最终会被宿主标记了该位置的内容替换(注意是替换,而不是插入),因此没必要对slot标签设置样式,这就是为啥chrome 53忽略其样式的原因,无独有偶,最新版的ios 10默认浏览器也会隐藏slot,因为slot中并不需要显示任何东西。

借鉴vue的思想,我们在编译阶段把slot编译成div,从而解决了这个问题,顺便提醒一下,shadow dom是非常新的技术,目前还处在试验阶段,而且标准还不确定,请不要在生产环境使用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容