>[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)
- 官网给的工具
- 声明vue2 和 vue3
- 指令速览
- Mustache -- 语法
- v-once -- 只渲染一次
- v-text -- 插入文本
- v-html -- 渲染html
- v-pre -- 显示原始的Mustache标签
- v-cloak -- 遮盖
- v-memo(新)-- 缓存指定值
- v-if/v-show -- 条件渲染
- v-for -- 循环
- v-bind -- 知识
- v-bind -- 修饰符
- v-on -- 点击事件
- v-model -- 双向绑定
- 其他基础知识速览
- 快速使用
- 常识知识点
- key -- 作用 (后续要更新)
- computed -- 计算属性
- watch -- 侦听
- 防抖和节流
- vue3 -- 生命周期
- vue-cli 和 vite 项目搭建方法
- vite -- 导入动态图片
- 组件
- 单文件组件 -- SFC
- 组件通信 -- porp
- 组件通信 -- $emit
- 组件通信 -- Provide / Inject
- 组件通信 -- 全局事件总线mitt库
- 插槽 -- slot
- 整体使用案例
- 动态组件 -- is
- keep-alive
- 分包 -- 异步组价
- mixin -- 混入
- v-model-- 组件
- 使用计算属性
- v-model -- 自定义修饰符
- Suspense -- 实验属性
- Teleport -- 指定挂载
- 组件实例 -- $ 属性
- Option API VS Composition API
- Setup -- 组合API 入口
- api -- reactive
- api -- ref
- 使用ref 和 reactive 场景
- api -- toRefs 和 toRef
- api -- readonly
- 判断性 -- API
- 功能性 -- API
- api -- computed
- api -- $ref 使用
- api -- 生命周期
- Provide 和 Inject
- watch
- watchEffect
- watch vs. watchEffect
- 简单使用composition Api
- 响应性语法糖
- css -- 功能
- 修改css -- :deep() 和 var
- Vue3.2 -- 语法
- ts -- vscode 配置
- attrs/emit/props/expose/slots -- 使用
- props -- defineProps
- props -- defineProps Ts
- emit -- defineEmits
- emit -- defineEmits Ts
- $ref -- defineExpose
- slots/attrs -- useSlots() 和 useAttrs()
- 自定义指令
- Vue -- 插件
- Vue2.x 和 Vue3.x 不同点
- $children -- 移除
- v-for 和 ref
- attribute 强制行为
- 按键修饰符
- v-if 和 v-for 优先级
- 组件使用 v-model -- 非兼容
- 组件
- h -- 函数
- jsx -- 编写
- Vue -- Router
- 了解路由和vue搭配
- vueRouter -- 简单实现
- 安装即使用
- 路由懒加载
- router-view
- router-link
- 路由匹配规则
- 404 页面配置
- 路由嵌套
- 路由组件传参
- 路由重定向和别名
- 路由跳转方法
- 命名路由
- 命名视图
- Composition API
- 路由守卫
- 路由元信息
- 路由其他方法 -- 添加/删除/获取
- 服务器配置映射
- 其他
- Vuex -- 状态管理
- Option Api -- VUEX
- composition API -- VUEX
- module -- VUEX
- 刷新后vuex 数据同步
- 小技巧
- Pinia -- 状态管理
- 开始使用
- pinia -- state
- pinia -- getter
- pinia -- action
- pinia -- 插件 ??
- Vue 源码解读
- 开发感悟
- 练手项目