概念:
类似于 Web Component
, Vue 提供的插槽也是作为模板标识替换的占位标签进行使用的
为什么需要有插槽?
- 插槽的使用本身也是为了弥补 props 传递时直观性不足的
- 对于复杂的模板数据,props,attrs 都是不易传递的
如何使用插槽?
基本使用:
在组件调用时使用插槽需要经历两个步骤:
- 在组件内部声明插槽
html
<template>
<slot></slot>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'MyComponent',
props: {
// ...
},
});
</script>
- 在调用组件的时候传入需要替换插槽的模板
html
<template>
<my-component>组件
<p>Content</p>
</my-component>
</template>
<script>
import { defineComponent } from 'vue';
import MyComponent from './components/MyComponent';
export default defineComponent({
name: 'App',
components: {
MyComponent
},
});
</script>
补充
- slot 可以理解成是一个 vue 的内置组件
- slot 的调用机制可以理解成是定义了一个回调函数,组件调用时触发这个回调函数
- 在不传递 name(通常我们称之为匿名插槽 )时,slot 的 name 为
default
使用单个插槽示例:
在组件调用使用插槽时,我们可以在插槽中传递:
- 文本
- 元素(单个或多个)
- 组件 (单个或多个)
html
<!-- 直接插入文本 -->
<my-component>
balala
</my-component>
<!-- 插入其他的模板元素 -->
<MyComponent>
<h2>content</h2>
</MyComponent>
<!-- 插入组件 -->
<my-component>
<component-1 />
<component-2 />
<component-3 />
</my-component>
总结 - 定义插槽的规则:
- 在 slot 中可以插入文本, HTML, 组件
- 在定义 slot 的时候, 之间的值是默认值
- 组件的属性 props 是私有的, 不能够在插槽中直接访问
- 在匿名插槽定义多个元素时,最好使用
<template>
包裹一下
具名插槽
为啥插槽还需要写名字呢?
有时候,我们的组件有多个不确定渲染的位置,这个时候我们就需要使用具名插槽了。
基本使用:
具名插槽的使用步骤和匿名插槽是几乎一样的
- 在组件内部声明插槽
html
<template>
<div>
<slot name="header"></slot>
<slot name="default"></slot>
<slot name="footer"></slot>
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'MyComponent2',
props: {
// ...
},
});
</script>
- 在调用组件的时候传入需要替换插槽的模板
html
<template>
<div>
<MyComponent2>
<template #header>
<header>Header</header>
</template>
<template #default>
<section>Content</section>
</template>
<template #footer>
<footer>
Footer
</footer>
</template>
</MyComponent2>
</div>
</template>
<script>
import { defineComponent } from 'vue';
import MyComponent2 from './components/MyComponent2.vue';
export default defineComponent({
name: 'App',
components: {
MyComponent2
},
});
</script>
具名插槽的一些注意点:
-
通过 name 定位匹配替换的相应的内容, 组件调用时可以替换多个不同的 slot
-
用法 v-slot:name (语法糖
#name
) -
原则上,
v-slot
只能用在 template 上面 -
结合具名函数和匿名函数进行对比 (将一个具名函数(匿名函数)赋值给一个js变量)
jsvar foo = function () {}; var foo = function foo1() {}
-
v-slot:default
可以替换一个匿名插槽 -
使用v-slot时, 可以同时替换多个匿名插槽
-
可以在组件中声明多个具名插槽位
作用域插槽
- 和组件一样, slot 中也可以传递 props 属性值, 用户可以在使用插槽时在 v-slot 中接收到这些值
html
<template>
<div class="comp">
<slot name="default" :myId="myId" :myName="myName"></slot>
<slot name="footer"></slot>
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'MyComponent3',
props: {
id: Number,
name: String
},
data() {
return {
myId: -1,
myName: 'hahaha'
};
},
mounted() {
this.myId = this.id;
this.myName = this.name;
setTimeout(() => {
this.myName = 'Baby Wong';
}, 2000);
}
});
</script>
html
<template>
<MyComponent3 :id="1" name="王宝宝">
<template #default="{ myId, myName }">
<p>ID: {{ myId }}</p>
<p>Name: {{ myName }}</p>
</template>
</MyComponent3>
</template>
<script>
import { defineComponent } from 'vue';
import MyComponent3 from './components/MyComponent3.vue';
export default defineComponent({
name: 'App',
components: {
MyComponent3
}
});
</script>
-
使用作用域插槽时, 如果没有其他的插槽, 可以使用
v-slot="xxx"
/#default=""
-
如果容器只有默认一个插槽,可以直接在容器上面v-slot获取值 (props | 解构) (这是唯一的一种情况, v-slot可以在非 template 上写)
-
类似ES6
- v-slot 插槽可以支持解构 (类似ES6对象解构)
- v-slot插槽可以有默认值(ES6 解构默认值)
动态插槽
- 在不确定使用什么插槽时, 我们可以通过数据动态控制渲染的插槽v-slot:[slotName]
- 动态插槽用的比较少,了解一下即可
html
<template>
<Comp v-slot:[slotName] />
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'App',
computed: {
slotName() {
const num = Math.random();
if (num > .5) {
return 'main';
}
return 'default';
}
}
});
</script>