Vue3(其实从2.6开始)中引入了一个新的指令v-slot
,用来表示具名插槽和默认插槽
<foo v-slot="{ msg }">
{{ msg }}
foo>
<foo>
<template v-slot:one="{msg}">
{{ msg }}
template>
foo>
在v2.5中介绍了slot-scope
,可以直接在插槽元素上使用。
<foo>
<div slot-scope="{ msg }">
{{ msg }}
div>
foo>
同样的,我们也可以在组件上这样使用。
<foo>
<bar slot-scope="{ msg }">
{{ msg }}
bar>
foo>
然而,上面的示例会导致一个问题:slot-scope
的位置不能清晰的反映出这个作用域变量是哪一个 组件提供的。上面例子中slot-scope
是写在
组件上,但是实际上这个作用域变量的定义是有
组件的默认插槽提供的。
当嵌套的层级越深,情况就会变得越糟。
<foo>
<bar slot-scope="foo">
<baz slot-scope="bar">
<div slot-scope="baz">
{{ foo }} {{ bar }} {{ baz }}
div>
baz>
bar>
foo>
像上面这种情况,我们无法立即分辨出模板上作用域变量是由那一个组件提供的。
v-slot
我们可以在slot容器上使用
v-slot
来表示一个传入组件的插槽,通过指令参数来表示插槽的名称。
<foo>
<template v-slot:header>
<div class="header">div>
template>
<template v-slot:body>
<div class="body">div>
template>
<template v-slot:footer>
<div class="footer">div>
template>
foo>
作用域插槽的内部工作原理是将插槽的内容包裹在一个函数里
function(slotProps){
// 插槽内容
}
这就意味着v-slot
的值实际上可以是任何能够作为函数定义中的参数的Javascript表达式,所以在支持的环境下 (单文件组件或现代浏览器),你也可以使用 ES2015 解构来传入具体的插槽 prop,如下:
<foo>
<template v-slot:header="{ msg }">
<div class="header">
Message from header slot: {{ msg }}
div>
template>
foo>
v-slot
可以直接用在组件上,如果没有参数,则表示默认的作用域插槽,传递给默认插槽的属性应该作为变量在其属性值声明。
<foo v-slot="{ msg }">
{{ msg }}
foo>
对于常用的场景(只有一个默认的作用域插槽)
<foo v-slot="{msg}">{{msg}}foo>
作用域变量与组件之间的联系更加的清晰
<foo>
<bar slot-scope="foo">
<baz slot-scope="bar">
<div slot-scope="baz">
{{ foo }} {{ bar }} {{ baz }}
div>
baz>
bar>
foo>
使用新语法也可以达到同样的效果
<foo v-slot="foo">
<bar v-slot="bar">
<baz v-slot="baz">
{{ foo }} {{ bar }} {{ baz }}
baz>
bar>
foo>
注意:组件提供的作用域变量依然声明在当前组件上,新的语法更清晰的展示出组件与作用域变量的关系。(父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。)
动态指令参数也可以用在 v-slot
上,来定义动态的插槽名:
<foo>
<template v-slot:[slotName]>
...
template>
foo>
和 v-bind
和v-on
相似,缩写只有在存在参数时才生效,这就意味着v-slot
没有参数时不能使用#=
,对于默认插槽,可以使用#default
来代替v-slot
<foo>
<template v-slot:header="{ msg }">
Message from header: {{ msg }}
template>
<template v-slot:footer>
A static footer
template>
foo>
<foo>
<template #header="{ msg }">
Message from header: {{ msg }}
template>
<template #footer>
A static footer
template>
foo>
<foo v-slot="{ msg }">
{{ msg }}
foo>
<foo #default="{ msg }">
{{ msg }}
foo>
<foo>
<template slot-scope="{ msg }">
{{ msg }}
template>
foo>
<foo v-slot="{ msg }">
{{ msg }}
foo>
<foo>
<div slot-scope="{msg}">
{{msg}}
div>
foo>
<foo v-slot="{msg}">
<div>
{{msg}}
div>
foo>
<foo>
<bar slot-scope="foo">
<baz slot-scope="bar">
<template slot-scope="baz">
{{ foo }} {{ bar }} {{ baz }}
template>
baz>
bar>
foo>
<foo v-slot="foo">
<bar v-slot="bar">
<baz v-slot="baz">
{{ foo }} {{ bar }} {{ baz }}
baz>
bar>
foo>
<foo>
<template slot="one" slot-scope="{ msg }">
text slot: {{ msg }}
template>
<div slot="two" slot-scope="{ msg }">
element slot: {{ msg }}
div>
foo>
<foo>
<template v-slot:one="{ msg }">
text slot:{{msg}}
template>
<template v-slot:two="{msg}">
<div>
element slot: {{msg}}
div>
template>
foo>
<foo>
<bar slot="one" slot-scope="one">
<div slot-scope="bar">
{{ one }} {{ bar }}
div>
bar>
<bar slot="two" slot-scope="two">
<div slot-scope="bar">
{{ two }} {{ bar }}
div>
bar>
foo>
<foo>
<template v-slot:one="one">
<bar v-slot="bar">
<div>{{ one }} {{ bar }}div>
bar>
template>
<template v-slot:two="two">
<bar v-slot="bar">
<div>{{ two }} {{ bar }}div>
bar>
template>
foo>
this.$slots.slotName()
this.$slots.foo()
this.$slots.default()