前言
插槽是定义在子组件中的,相当于一个占位符,父组件可以在这个占位符中填充HTML代码、组件等内容。
插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制。
基本使用
子组件:
<template><div><h1>今天天气状况:</h1><slot></slot></div>
</template><script>
export default {name: 'child'
}
</script>
父组件:
<template><div class="box"><div>使用slot分发内容</div><child><div>多云</div></child></div>
</template><script>
import Child from './Child.vue';
export default {components: { Child },
};
</script><style scoped>
.box {margin: 20px;
}
</style>
如果把子组件中 slot 去掉,父组件不变:
<template><div><h1>今天天气状况:</h1><!-- <slot></slot> --></div>
</template><script>
export default {name: 'child'
}
</script>
如果子组件没有使用插槽,父组件如果需要往子组件中填内容是没法做到的。
具名插槽
具名插槽其实就是给插槽取个名字。一个子组件可以放多个插槽,而且可以放在不同的地方,而父组件填充内容时,可以根据这个名字把内容填充到对应插槽中。
子组件
<template><div><div class="top"><h1>头部</h1><slot name="top"></slot> <!--具名插槽1--></div><div class="center"><h1>中间</h1><slot></slot> <!--默认插槽--></div><div class="bottom"><h1>底部</h1><slot name="bottom"></slot> <!--具名插槽2--></div></div>
</template><script>
export default {name: "child",
};
</script><style scoped>
.top {background-color: aqua;
}
.center {background-color: pink;
}
.bottom {background-color: aquamarine;
}
</style>
父组件:
<template><div class="box"><div>使用slot分发内容</div><child><!--所有没指定插槽名称的会添加到默认插槽中--><div>A</div><div>B<span>C</span></div><!--具名插槽写法1--><div slot="bottom">E</div><!--具名插槽写法2--><template v-slot:top><div>D</div></template></child></div>
</template><script>
import Child from "./Child.vue";
export default {components: { Child },
};
</script><style scoped>
.box {margin: 20px;
}
</style>
无论父组件中插槽的顺序是怎样的,最终渲染结果都以子组件中插槽的顺序为准。
作用域插槽
作用域插槽其实就是带数据的插槽,简单的来说就是子组件提供给父组件的参数,该参数仅限于插槽中使用,父组件可根据子组件传过来的插槽数据来进行不同的方式展现和填充插槽内容。
子组件:
<template><div><h1>我是子组件</h1><slot :aa="list" bb="123"></slot></div>
</template><script>
export default {name: "child",data() {return {list: [1,2,3,4,5]}}
};
</script>
父组件:
<template><div class="box"><div>我是父组件</div><child><div slot-scope="ss1"><!--ss1这个名字是随便取的-->{{ ss1 }}<div>呵呵</div></div></child><hr /><child><div slot-scope="{ bb }"> <!--括号中的属性名必须是子组件中存在的-->{{ bb }}<div>嘻嘻</div></div></child><hr /><child><ul slot-scope="ss2"><li v-for="(item, index) in ss2.aa" :key="index">{{ item }}</li></ul></child><hr /><child> 哈哈 </child></div>
</template><script>
import Child from "./Child.vue";
export default {components: { Child },
};
</script><style scoped>
.box {margin: 20px;
}
</style>
使用场景:如果子组件中的某一部分的数据,每个父组件都会有自己的一套对该数据的不同的呈现方式,这时就需要用到作用域插槽。
Vue2 和 Vue3 写法的区别
主要是一些写法上的区别
具名插槽
Vue2:
<!--子组件-->
<slot name="top"></slot><!--父组件-->
<div slot="top">xxx</div>
Vue3:
<!--子组件-->
<slot></slot>
<slot name="top"></slot><!--父组件-->
<template v-slot><div>xxx</div>
</template><template #default><div>xxx</div>
</template><template v-slot:top><div>xxx</div>
</template><template #top><div>xxx</div>
</template>
作用域插槽
Vue2:
<!--子组件-->
<slot :aa="list" bb="123"></slot>
// list: [ 1, 2, 3, 4, 5 ]<!--父组件-->
<div slot-scope="ss1">{{ ss1 }} //输出 { "aa": [ 1, 2, 3, 4, 5 ], "bb": "123" }
</div><div slot-scope="{ bb }"> <!--括号中的属性名必须是子组件中存在的-->{{ bb }} // 输出 123
</div>
Vue3:
<!--子组件-->
<slot :aa="list" bb="123" name="top"></slot><!--父组件-->
<template v-slot:top="ss1"><div>{{ ss1 }}</div> //输出 { "aa": [ 1, 2, 3, 4, 5 ], "bb": "123" }
</template><template v-slot:top="{ bb }"><div>{{ bb }}</div> // 输出 123
</template>
Vue3 写法扩展
<!--子组件-->
<template><div><h1>我是子组件</h1><slot :aa="list" bb="123"></slot><slot name="top"></slot></div>
</template><script>
export default {name: "child",data() {return {list: [1,2,3,4,5]}}
};
</script><style scoped>
</style>
<!--父组件-->
<template><div class="box"><div>我是父组件</div><child><template v-slot="ss1"><div>传递所有参数:{{ ss1 }}</div></template></child><child><template v-slot="{ bb }"><div>通过解构传递具体参数:{{ bb }}</div></template></child><child><template v-slot="{ bb: haha }"><div>参数重命名:{{ haha }}</div></template></child><child><template v-slot="{ cc = '默认值' }"><div>参数默认值:{{ cc }}</div></template></child><child><template v-slot:[slotName]="{ dd = '默认值' }"><div>动态插槽名和默认值:{{ dd }}</div></template></child></div>
</template><script>
import Child from "./Child.vue";
export default {components: { Child },data() {return {slotName: "top",};},
};
</script><style scoped>
.box {margin: 20px;
}
</style>