插槽在vue2.6.0开始有了新的更新
具名插槽(数据来自父组件)
子组件(定义插槽)这里版本前后没什么变化
<template> <div> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> </template> <script> export default { name: "BaseLayout" } </script>
父组件(使用)这里版本后废弃了slot="header"这样的写法,在vue3.0后直接移除。取而代之的是v-slot:插槽名称的写法,默认插槽(没有名字,默认为default),缩写为#header
<template> <base-layout> <template v-slot:header> <h1>Header</h1> </template> <template v-slot:default> <p>Main</p> </template> <template v-slot:footer> <p>Footer</p> </template> </base-layout> </template> <script> import BaseLayout from "../components/BaseLayout"; export default { components: {BaseLayout} } </script>
使用缩写#的代码
<template> <base-layout> <template #header> <h1>Header</h1> </template> <template #default> <p>Main</p> </template> <template #footer> <p>Footer</p> </template> </base-layout> </template> <script> import BaseLayout from "../components/BaseLayout"; export default { components: {BaseLayout} } </script>
页面
作用域插槽(数据来自子组件)【2.6.0起,v-slot取代了slot和slot-scope】
子组件(定义了数据并且将数据绑定到特定属性[user]上)
<template> <div> <header> <slot name="header"></slot> </header> <main> <!--绑定在 <slot> 元素上的特性被称为插槽 prop--> <slot :user="userData"> {{userData.lastName}} </slot> </main> <footer> <slot name="footer"></slot> </footer> </div> </template> <script> export default { name: "BaseLayout", data: () => ({ userData: { firstName: 'AAA', lastName: 'Miss' } }) } </script>
父组件(给 v-slot
带一个值来定义我们提供的插槽 prop 的名字[slotProps])这里废弃了slot="default" slot-scope="slotProps"的写法,直接v-slot:default="slotProps"或者#default="slotProps"
<template> <base-layout> <template #header> <h1>Header</h1> </template> <!--slotProps可以使任意名字--> <template #default="slotProps"> <strong style="color: crimson">{{slotProps.user.firstName}}</strong> </template> <template #footer> <p>Footer</p> </template> </base-layout> </template> <script> import BaseLayout from "../components/BaseLayout"; export default { components: {BaseLayout} } </script>
数据关系:
页面:
以上代码的意思是,本来这里的后备内容是显示lastName的,我们可以在父组件那里做手脚,让后备内容显示的是firstName。但是无论怎么做,数据都是来自子组件。
将父组件的指定的后备内容注释掉即可显示原生的内容,如下:
页面:
另外一个例子(写一个表格组件,灵感来源于Vuetify框架,没读过它的内部实现,但是一眼能看出使用了插槽,根据我的理解写出下面的例子)
定义:MyTable.vue
<template> <table> <slot name="headers"> <tr> <th v-for="h in headers" :key="h">{{h}}</th> </tr> </slot> <!--这里的插槽prop绑定了当前的数据 :items="i" --> <slot name="items" v-for="i in items" :items="i"> <tr :key="i[itemKey]" :title="i[itemKey]"> <td v-for="j in i" :key="j">{{j}}</td> </tr> </slot> </table> </template> <script> export default { name: "MyTable", // 自定义属性 props: ["headers","items","itemKey"], } </script> <style scoped> table{ width: 200px; margin: 25px auto; border-collapse: collapse; border: 1px solid #ddd; } table tr,table td{ border-collapse: collapse; border: 1px solid #ddd; padding: 8px 10px; } </style>
使用:
<template> <div class="about"> <!-- ********************作用域插槽的应用******************** --> <!--直接使用--> <my-table :headers="headersData" :items="itemsData" item-key="id"></my-table> <!--父组件利用插槽自定义--> <my-table :headers="headersData" :items="itemsData" item-key="id"> <!--有了作用域插槽,可以由父组件来改变子组件的展示效果--> <!--在父级作用域中,我们可以给 v-slot 带一个【值】来定义我们提供的插槽 prop 的名字--> <!--【值】也就是那个 props,可以为任意名字--> <template v-slot:items="props"> <tr> <td style="color: darkcyan">{{props.items.id}}</td> <td style="color: darkcyan">{{props.items.name}}</td> <td style="color: darkcyan">{{props.items.age}}</td> </tr> </template> </my-table> <!-- ********************作用域插槽的应用******************** --> </div> </template> <script> import MyTable from "../components/MyTable"; export default { name: 'about', components: {MyTable}, data: () => ({ headersData: ["ID", "Name", "Age"], itemsData: [ {id: 1, name: 'A', age: 10}, {id: 2, name: 'B', age: 20}, {id: 3, name: 'C', age: 12}, {id: 4, name: 'D', age: 15} ] }) } </script> <style scoped> </style>
页面:(前者直接使用,后者利用作用于插槽改变了颜色)
变量关系
其它
对于默认插槽,我们可以变成更加简洁的写法:
<template v-slot:default="slotProps"> <strong style="color: crimson">{{slotProps.user.firstName}}</strong> </template>
变成(不带参数的 v-slot
被假定对应默认插槽)
<template v-slot="slotProps"> <strong style="color: crimson">{{slotProps.user.firstName}}</strong> </template>
对于缩写 #,有限制条件,那就是只能有参数名的情况下才能使用,即:#header=“”。而不带的话会报错,即:#=“”