vm.$slots是一个对象,键名是所有具名slot的名称,加上一个default,而键值则是一个存放VNode节点的数组。
官网上提供的解释如下:
用来访问被
slot分发的内容。每个具名slot有其相应的属性
(例如:slot="foo"中的内容将会在vm.$slots.foo中被找到)
default 属性包括了所有没有被包含在具名 slot 中的节点。
示例如下:
<blog-post>
<h1 slot="header">
我属于header
</h1>
<h1 slot="header">
我也属于header
</h1>
<p>
我谁都不属于
</p>
<p slot="footer">
我属于footer
</p>
<p>
谁来认领我
</p>
</blog-post>
在blog-post标签里,元素们被这样的设置:
- 属于名称为
header的slot的有2个<h1> - 属于名称为
footer的slot的有1个<p> - 属于不具名
slot(会归到default里)的有2个<p>
尝试查看blog-post组件的$slots,得到结果如下:

vm.$slots
可以看到:
-
header对应一个长为2的数组,就是刚才那2个<h1>对应的VNode节点。 -
footer对应一个长为1的数组,就是刚才那1个<p>对应的VNode节点。 -
default对应一个长为6的数组,其中有4个是空的VNode节点(产生的原因尚不清楚),2个是刚才没有指定slot属性的<p>对应的VNode节点。
如果像下面这样,指定了render函数的话,就可以手动创建出html标签。
Vue.component('blog-post', {
render: function (createElement) {
var header = this.$slots.header
var body = this.$slots.default
var footer = this.$slots.footer
return createElement('div', [
createElement('header', header),
createElement('main', body),
createElement('footer', footer)
])
}
})
createElement(html标签名, VNode节点数组)会编译出一个指定的html标签,然后把VNode节点数组里非空的VNode节点编译回原来的html内容。其结果就相当于把原来的那些<blog-post>标签之间的内容根据它们的slot属性,放进了指定的标签里。
刚刚的例子里,最终编译出的html结构如下:

html结构