💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
>[success] # 插槽 -- slot 1. 插槽作用就是对组件可以暴露特定位置,能在外部需要添加一些自定的代码,可以理解为提供预留项 2. 如果组件不使用插槽但方面在使用组件时候在标签中写下内容,组件渲染时候中间内容会忽略: ` <com><div>在com组件中我是不可以直接插入的</div> </com>` 3. 声明使用插槽时候需要先在组件内部提供一个**插槽出口**,这样在使用组件时候就可以在其提供的出口出加上**插槽内容**,进行渲染 4. 可以插入普通的内容、html元素、组件,都可以是可以的 ![](https://img.kancloud.cn/a4/14/a4146a41fc028f2eec5ae5223bc51a4e_771x282.png) >[danger] ##### 插槽作用 1. 插槽的使用过程其实是抽取共性、预留不同; 2. 会将共同的元素、内容依然在组件内进行封装; 3. 同时会将不同的元素使用slot作为占位,让外部决定到底显示什么样的元素; >[info] ## 使用默认插槽 1. ` <slot>` 元素作为**组件内部**承载分发内容,就可以为封装组件开启一个插槽 2. 插槽中的值取决于**父组件如何使用** * 父组件 ~~~html <template> <children-todo> <div>插入内容</div> </children-todo> </template> <script> import childrenTodo from './components/children-todo.vue' export default { name: 'App', components: { childrenTodo, }, } </script> <style></style> ~~~ * 子组件 ~~~html <template> <div class="content"> <div class="left"> <slot></slot> </div> <div class="center"> <slot></slot> </div> <div class="right"> <slot></slot> </div> </div> </template> <script> export default {} </script> <style scoped> .content { display: flex; } .left, .right { width: 80px; } .left, .right, .center { height: 44px; } .left, .right { width: 80px; background-color: red; } .center { flex: 1; background-color: blue; } </style> ~~~ * 效果 ![](https://img.kancloud.cn/81/ca/81cab4cd9afd926f5addca2105f97c05_387x114.png) >[danger] ##### 插槽默认值 1. 可以给插槽中内容设置默认值,当在父组件使用的时候,没有提供任何插槽内容时会显示设置的默认内容 * 子组件 ~~~ <button type="submit"> <slot>1234</slot> </button> ~~~ * 父组件 ~~~ <submit-button></submit-button> ~~~ ![](https://img.kancloud.cn/50/cf/50cf4e4ab3050bd08e3326a34ade5bbd_191x46.png) >[info] ## 具名插槽 1. 可以通过给插槽起名字指定的预留位置,让插槽具有多个出口 2. `<slot>` 元素有一个特殊的` attribute:name` 用来指定名字 3. 个不带 `name `的`slot`,会带有隐含的名字 `default`,`<slot>`其实是`<slot name="defatult">` ~~~ <template #default> <p>A paragraph for the main content.</p> <p>And another one.</p> </template> ~~~ 4. 在使用时候需要使用`template `包裹并且在`template `声明渲染的插槽使用`v-solt:名字`指定具体渲染插槽,可以使用 **#名字作为缩写** ![](https://img.kancloud.cn/44/59/4459146974f7facdd3be3c8add5ad997_664x287.png) * 子组件 ~~~ html <template> <div class="content"> <div class="left"> <slot name="left"></slot> </div> <div class="center"> <slot name="center"></slot> </div> <div class="right"> <slot name="right"></slot> </div> </div> </template> <script> export default {} </script> <style scoped> .content { display: flex; } .left, .right { width: 80px; } .left, .right, .center { height: 44px; } .left, .right { width: 80px; background-color: red; } .center { flex: 1; background-color: blue; } </style> ~~~ * 父 ~~~html <template> <children-todo> <template v-slot:left> <div>左面内容</div> </template> <template #center> <div>中间内容</div> </template> <template #right> <div>右侧内容</div> </template> </children-todo> </template> <script> import childrenTodo from './components/children-todo.vue' export default { name: 'App', components: { childrenTodo, }, } </script> <style></style> ~~~ >[info] ## 动态插槽 1. 目前我们使用的插槽名称都是固定的 ,比如` v-slot:left、v-slot:center`等等,我们可以通过 `v-slot:[dynamicSlotName]`方式动态绑定一个名称; >[danger] ##### 使用 ~~~ 1.组件内容slot 动态就是通过v-bind 绑定 name 即可 2.在父组件使用时候想动态需要使用'[]'包裹属性值参数 ~~~ * 子 ~~~ <div class="center"> <slot :name="center"></slot> </div> ~~~ * 父 ~~~html <base-layout> <template v-slot:[dynamicSlotName]> ... </template> <!-- 缩写为 --> <template #[dynamicSlotName]> </base-layout> <script> export default { data() { return { dynamicSlotName: "center", } } } </script> ~~~ >[info] ## 作用域插槽 1. 父级模板里的所有内容都是在父级作用域中编译的;子组件模板里的所有内容都是在子作用域中编译的调用,**虽然插槽会帮我们在子组件预留位置但仅仅是视图上的预留并不是数据之间的** 2. 作用域插槽可以形成一种 **子传父的效果**,将子组件的以些值通过插槽位置传递个父组件 ![](https://img.kancloud.cn/2b/94/2b94608dd2af50b5fc6099079dcd734d_526x445.png) >[danger] ##### 使用作用域插槽解决问题 1. 在子组件 `slot` 标签上去指定想要传递给父组件的值,例如想把下面的todos 传递给父组件 ~~~ <div class="center"> <slot name="center" :todos="todos"></slot> </div> ~~~ 在使用插槽位置获取,因为你在slot 哪里可能会传入很多值,因此获取的值其实为对象,支持解构形式也就是说如果你`<template #center="aa"> `这么写此时`aa `为` {todos:[]}` ~~~ <template #center="{ todos }"> <a v-for="(todo, index) in todos" :key="index">{{ todo }}</a> </template> ~~~ 2. 传递值中`name `是一个 `Vue `特别保留的 `attribute`,不会作为 `props `传递给插槽,所以下面案例中除了name 他的值都会传递到父组件 * 子 ~~~html <template> <div class="container"> <slot name="t" value="12" id="13" msg="14" :childrenData="ls"></slot> </div> </template> <script> export default{ data(){ return { ls:["1",2] } } } </script> <style> footer { border-top: 1px solid #ccc; color: #666; font-size: 0.8em; } </style> ~~~ * 父 ~~~html <script> import BaseLayout from './BaseLayout.vue' export default { components: { BaseLayout } } </script> <template> <BaseLayout> <template #t="data"> {{data}} </template> </BaseLayout> </template> ~~~ * 效果 ![](https://img.kancloud.cn/40/51/405151483541be8ca1d4f4613f116a04_589x75.png) >[danger] ##### 更多案例 * 父 ~~~html <template> <children-todo> <template v-slot:left> <div>左面内容</div> </template> <template #center="{ todos }"> <a v-for="(todo, index) in todos" :key="index">{{ todo }}</a> </template> <template #right> <div>右侧内容</div> </template> </children-todo> </template> <script> import childrenTodo from './components/children-todo.vue' export default { name: 'App', components: { childrenTodo, }, } </script> <style></style> ~~~ * 子 ~~~html <template> <div class="content"> <div class="left"> <slot name="left"></slot> </div> <div class="center"> <slot name="center" :todos="todos"></slot> </div> <div class="right"> <slot name="right"></slot> </div> </div> </template> <script> export default { data() { return { todos: [1, 2, 3, 4, 5], } }, } </script> <style scoped> .content { display: flex; } .left, .right { width: 80px; } .left, .right, .center { height: 44px; } .left, .right { width: 80px; background-color: red; } .center { flex: 1; background-color: blue; } </style> ~~~ * 渲染结果 ![](https://img.kancloud.cn/05/50/0550b030414ae7b9967ae1d8775ed4f9_397x149.png) >[danger] ##### 独占默认插槽的缩写语法 1. 只有默认插槽使用使用默认插槽作用域可以从 ~~~html <todo-list v-slot:default="slotProps"> <template #default="slotProps"> <i class="fas fa-check"></i> <span class="green">{{ slotProps.item }}</span> </template > </todo-list> ~~~ * 简写 忽略`template` ~~~html <todo-list v-slot:default="slotProps"> <i class="fas fa-check"></i> <span class="green">{{ slotProps.item }}</span> </todo-list> ~~~ * 或者 缩写 ~~~ <todo-list v-slot="slotProps"> <i class="fas fa-check"></i> <span class="green">{{ slotProps.item }}</span> </todo-list> ~~~ * 但是如果既有默认插槽 又有命名插槽那就不能使用上面缩写 * 注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确: ~~~html <!-- 无效,会导致警告 --> <todo-list v-slot="slotProps"> <i class="fas fa-check"></i> <span class="green">{{ slotProps.item }}</span> <template v-slot:other="otherSlotProps"> slotProps 在此处不可用 </template> </todo-list> ~~~ * 只要出现多个插槽,请始终为所有的插槽使用完整的基于 <template> 的语法: ~~~html <todo-list> <template v-slot:default="slotProps"> <i class="fas fa-check"></i> <span class="green">{{ slotProps.item }}</span> </template> <template v-slot:other="otherSlotProps"> ... </template> </todo-list> ~~~ >[info] ## 官网 [可以看一下官网最后两个实例](https://cn.vuejs.org/guide/components/slots.html#scoped-slots)