Vue 2.6.0 以前 | Vue 2.6.0 以后 |
---|---|
具名插槽 slot
|
具名插槽 v-slot
|
作用域插槽 slot-scope = slotProps
|
作用域插槽 v-slot: [name] = slotProps
|
这里我们要讨论的不是怎么用,而是比较少有探究的 slot
, slot-scope
以及 v-slot
, v-slot:[name] = slotProps
与 $slots
, $scopedSlots
的关系,一般在应用中不涉及渲染函数,很少用得到$slots
和 $scopedSlots
,但是在深入理解插槽的实现和二次封装 UI库 的时候就可能用得上了。
一、 slot
,slot-scope
和 $slots
, $scopedSlots
的关系
1. 无作用域插槽
HTML
<div id="parent-template">
<child>
<!--此处是待分发的内容-->
<p slot="header">header</p>
<p slot="footer">footer</p>
<p>default</p>
</child>
</div>
<template id="child-template">
<div>
<slot name="header"></slot>
<slot>默认分发处</slot>
<slot name="footer"></slot>
</div>
</template>
JS
// 注册子组件
Vue.component("child", {
template:"#child-template",
mounted() {
console.log('$slots',this.$slots)
console.log('$scopedSlots',this.$scopedSlots)
}
});
// 初始化父组件
new Vue({
el: "#parent-template"
});
Console 输出
这是一个常用的插槽模板,从这个结果中可以看出v2.6.0以前,slot 和 slot-scope是分开的 ;
v2.6.0以前父组件没有调用 slot-scope
时, $scopedSlots
里面为空 ;
v2.6.0以后 $scopedSlots
里的具名值和 $slots
具名值是一一对应的。
2. 有作用域插槽
HTML
<div id="parent-template">
<child>
<!--此处是待分发的内容-->
<p slot="header" slot-scope="{header}">{{ header }}</p>
<p slot="footer">footer</p>
<p>default</p>
</child>
</div>
<template id="child-template">
<div>
<slot name="header" v-bind:header="'header'"></slot>
<slot>默认分发处</slot>
<slot name="footer" v-bind:footer="'footer'"></slot>
</div>
</template>
v2.6.0以前,在父组件中'header'具名插槽中调用了slot-scope
后,$scopedSlots
中出现了‘header’为key的function, $slots
中‘header’为key的VNode不见了;
v2.6.0以后,在父组件中'header'具名插槽中调用了slot-scope后,$scopedSlots
中没有变化, $slots
中‘header’为key的VNode不见了。
3. 多次调用同一个具名插槽
HTML
<div id="parent-template">
<child>
<!--此处是待分发的内容-->
<p slot="header">header</p>
<div slot="header">header1</div>
<p slot="footer">footer</p>
<p>default</p>
</child>
</div>
<template id="child-template">
<div>
<slot name="header" v-bind:header="'header'"></slot>
<slot>默认分发处</slot>
<slot name="footer" v-bind:footer="'footer'"></slot>
</div>
</template>
Console 输出
从输出结果可以看出老式写法在v2.6.0以前和以后都能在$slots
里有两个header的具名插槽内容,这与后面新式写法就有不同。
二、v-slot
, v-slot:[name]=slotProps
和 $slots
, $scopedSlots
的关系
1. 无作用域插槽
HTML
<div id="parent-template">
<child>
<!--此处是待分发的内容-->
<template v-slot:header>
<p>{{ header }}</p>
</template>
<template v-slot:footer>
<p>footer</p>
</template>
<template v-slot:default>
<p>default</p>
</template>
</child>
</div>
<template id="child-template">
<div>
<slot name="header"></slot>
<slot>默认分发处</slot>
<slot name="footer"></slot>
</div>
</template>
Console输出
从输出可以看出,新式写法在v2.6.0版本后,default中tag 为 undfined
的元素没有了,并且$slots
中的内容是后面塞进去的,$scopedSlots
一开始就有。
2. 有作用域插槽
HTML
<div id="parent-template">
<child>
<!--此处是待分发的内容-->
<template v-slot:header="{header}">
<p>{{ header }}</p>
</template>
<template v-slot:footer>
<p>footer</p>
</template>
<template v-slot:default>
<p>default</p>
</template>
</child>
</div>
<template id="child-template">
<div>
<slot name="header" v-bind:header="'header'"></slot>
<slot>默认分发处</slot>
<slot name="footer" v-bind:header="'footer'"></slot>
</div>
</template>
Console 输出
这个输出同老式写法在v2.6.0版本后的输出一样,除了一开始$slots
里面没有值,是后面塞进去的。
3. 多次调用同一个具名插槽
HTML
<div id="parent-template">
<child>
<!--此处是待分发的内容-->
<template v-slot:header>
<p>header</p>
</template>
<template v-slot:header>
<p>header1</p>
</template>
<template v-slot:footer>
<p>footer</p>
</template>
<template v-slot:default>
<p>default</p>
</template>
</child>
</div>
<template id="child-template">
<div>
<slot name="header" v-bind:header="'header'"></slot>
<slot>默认分发处</slot>
<slot name="footer" v-bind:header="'footer'"></slot>
</div>
</template>
Console输出
从输出可以看出,新式写法多次调用同一个具名插槽,后面的会覆盖前面的,这个和老是写法一个比较大的区别,在升级的时候就要特别注意。
小结
经过上面的实践对比,有以下几点结论:
- v2.6.0以后在
$slots
里可以取到具名key,在$scopedSlots
都能取到; - v2.6.0以后
v-slot
的写法不能多次使用同名的具名插槽,后面的会覆盖前面的,不会显示两个同名具名插槽的内容; - v2.6.0以后用
v-slot
的写法,如果在子组件中用$slot
,一定调用watch方法,因为一开始$slots
为空,后面才塞入的数据。