Vue.js 自 2.6.0 起有所更新,已废弃使用 slot-scope 属性语法。
有时让插槽内容能够访问子组件中才有的数据是很有用的。例如,设想一个带有如下模板的 <current-user> 组件:
<span> <slot>{{ user.lastName }}</slot> </span>
我们可能想换掉备用内容,用名而非姓来显示。如下:
<current-user> {{ user.firstName }} </current-user>
然而上述代码不会正常工作,因为只有 <current-user> 组件可以访问到 user,而我们提供的内容是在父级渲染的。
为了让 user 在父级的插槽内容中可用,我们可以将 user 作为 <slot> 元素的一个属性绑定上去:
<span> <!-- 将 current-user 组件中的 user 对象绑定到 slot 中名为 user 的 prop --> <slot v-bind:user="user"> {{ user.lastName }} </slot> </span>
绑定在 <slot> 元素上的属性被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字,例如:
<current-user> <!-- 利用 v-slot 将组件中 slot 所有 prop 对象命名为 slotProps --> <template v-slot:default="slotProps"> {{ slotProps.user.firstName }} </template> </current-user>
在这个例子中,我们选择将包含所有插槽 prop 的对象命名为 slotProps,但你也可以使用任意你喜欢的名字。
(1)如果被提供的内容只有默认插槽时,可以把 v-slot 直接用在组件上,例如:
<current-user v-slot:default="slotProps"> {{ slotProps.user.firstName }} </current-user>
(2)更简单的写法,不带参数的 v-slot 被假定对应默认插槽,例如:
<current-user v-slot="slotProps"> {{ slotProps.user.firstName }} </current-user>
注意:默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确:
<!-- 无效,会导致警告 --> <current-user v-slot="slotProps"> {{ slotProps.user.firstName }} <template v-slot:other="otherSlotProps"> slotProps is NOT available here </template> </current-user>
只要出现多个插槽,请始终为所有的插槽使用完整的基于 <template> 的语法:
<current-user> <template v-slot:default="slotProps"> {{ slotProps.user.firstName }} </template> <template v-slot:other="otherSlotProps"> ... </template> </current-user>
作用域插槽的内部工作原理是将你的插槽内容包裹在一个拥有单个参数的函数里,例如:
function (slotProps) { // 插槽内容 }
这意味着 v-slot 的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式。所以在支持的环境下 (单文件组件或现代浏览器),你也可以使用 ES2015 解构来传入具体的插槽 prop,如下:
<current-user v-slot="{ user }"> {{ user.firstName }} </current-user>
这样可以使模板更简洁,尤其是在该插槽提供了多个 prop 的时候。它同样开启了 prop 重命名等其它可能,例如将 user 重命名为 person:
<current-user v-slot="{ user: person }"> {{ person.firstName }} </current-user>
你甚至可以定义默认内容,用于插槽 prop 是 undefined 的情形,例如:
<current-user v-slot="{ user = { firstName: 'Guest' } }"> {{ user.firstName }} </current-user>
<html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue</title> <!-- 使用 CDN 引入 Vue 库 --> <!-- <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> --> <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.9/vue.js"></script> </head> <body> <div id="app"> <!-- 不提供插槽内容,使用默认值 --> <current-user v-bind:user="user"></current-user> <!-- 提供插槽 --> <current-user v-bind:user="user"> <!-- 利用 v-slot 将组件中 slot 所有 prop 对象命名为 slotProps --> <template v-slot:default="slotProps"> {{ slotProps.user.firstName }} </template> </current-user> </div> <script type="text/javascript"> Vue.component('current-user', { props: [ "user" ], template: ` <span style="display:block;background:red;margin:10px;"> <!-- 将 current-user 组件中的 user 对象绑定到 slot 中名为 user 的 prop --> <slot v-bind:user="user"> {{ user.lastName }} </slot> </span> ` }); var app = new Vue({ el: "#app", data: { user: { firstName: "张", lastName: "山" } } }); </script> </body> </html>
运行效果如下图: