基础
作用
插槽
就是给子组件添加模板字段的方式,让插入的模板在子组件中进行渲染。
代码示例
1 2 3 4 5 6 7 8
| <FancyButton> Click me! <!-- 插槽内容 --> </FancyButton>
<!-- FancyButton组件内容 --> <button class="fancy-btn"> <slot></slot> <!-- 插槽出口 --> </button>
|
说明
<slot>
元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。
作用域
插槽内容在哪个组件当中,那他使用的数据就是哪个组件的,跟他最后渲染到哪个组件里面没有任何关系。
- 插槽内容可以访问父组件数据【因为插槽内容本来就在父组件定义】
- 茶插槽内容不能访问子组件数据
插槽后备内容
在slot
标签内部添加内容,在没有给组件内部写内容时,插槽的默认内容为slot标签内部的内容。
具名插槽
对于单个子组件内部需要不同地方使用插槽,这个时候如果没有区分的话,那么每个插槽内部都会获取到该组件内部的所有内容,所以为了让不同的内容到对应的位置去,就有了具名插槽
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <!-- 父组件 --> <Card :content="content"> <div>社区小贴</div> <div>测试数据测试数据</div> <div>1235321478</div> </Card>
<!-- 子组件 --> <template> <div class=""> <header><slot /></header> <main><slot /></main> <footer><slot /></footer> </div> </template>
|
这种情况就是每个标签内部都会显示出着三条内容。
1 2 3 4 5 6 7 8 9
| <!-- 此时所有的内容都会显示在默认插槽内部,也就是下面的 <slot />内 --> <template> <div class=""> <slot /> <header><slot name="header" /></header> <main><slot name="main" /></main> <footer><slot name="footer" /></footer> </div> </template>
|
<slot />
等同于<slot name="default"/>
- 所以就是说所有的插槽都有自己的名字。
- 将插槽内容放置到自己对应的内容下的方法:
1 2 3 4 5 6
| <Card :content="content"> <template v-slot:header>社区小贴</template> <template #main>测试数据测试数据</template> <template #footer>1235321478</template> <template #default>1235321478</template> </Card>
|
- 将标签改为
template
标签,然后使用v-slot
就可以实现
- 同样的也可以使用
#
+slot的name属性
简写来实现
插槽props使用
先来实现一个小功能。对于一个列表,每条数据需要一个删除功能,之前的写法是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <!-- 父组件 --> <template> <Lesson v-for="item in data" :key="item.id" :lesson="item" @del="del"></Lesson> </template> <script> export default { methods: { del(lesson) { const index = this.data.findIndex(l => l.id == lesson.id);
this.data.splice(index, 1); } } } </script>
<!-- 子组件 --> <template> <div> {{ lesson.title }} <button @click="del">删除</button> </div> </template> <script> export default { props: ['lesson'], emits: ['del'], data() { return {
} }, methods: { del() { this.$emit('del', this.lesson); } } </script>
|
现在使用插槽可以快速实现:
方式一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <!-- 父组件 --> <template> <Lesson v-for="item in data" :key="item.id" :lesson="item"> <button @click="del(item)">删除</button> </Lesson> </template> <script> export default { methods: { del(lesson) { const index = this.data.findIndex(l => l.id == lesson.id);
this.data.splice(index, 1); } } } </script>
<!-- 子组件 --> <template> <div class=""> {{ lesson.title }} <slot></slot> </div> </template>
|
- 这种方式插槽内部可以直接使用父组件数据,不用来回传递方法。
方式二
- 先来熟悉一下使用slot的props将子组件参数传递给父组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <!-- 子组件 --> <template> <div class=""> {{ lesson.title }} <slot content="name"></slot> </div> </template>
<!-- 父组件 --> <Lesson v-for="item in data" :key="item.id" :lesson="item"> <template v-slot:default="slotProps"> {{ slotProps }} <!-- {"content": "name"} 可以拿到子组件slot标签上的属性值 --> <button>删除</button> </template> </Lesson>
|
需要准确拿到对应属性值,可以定义多个变量:
1 2 3 4 5 6 7
| <!-- 父组件 --> <Lesson v-for="item in data" :key="item.id" :lesson="item"> <template v-slot:default="{content}"> {{ content }} <!-- name 可以拿到子组件slot标签上的content属性的值 --> <button>删除</button> </template> </Lesson>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <!-- 父组件 --> <Lesson v-for="item in data" :key="item.id" :lesson="item"> <template #default="{id}"> <button>删除</button> </template> </Lesson> <script> export default { methods: { del(id) { const index = this.data.findIndex(l => l.id == id);
this.data.splice(index, 1); } } } </script>
<!-- 子组件 --> <template> <div> {{ lesson.title }} <slot :id="lesson.id"></slot> </div> </template>
|
独占默认插槽使用
对于上面的子组件只有一个默认插槽时,此时父组件可以简写为以下形式也能实现形同效果:
1 2 3
| <Lesson v-for="item in data" :key="item.id" :lesson="item" #default="{id}"> <button>删除</button> </Lesson>
|
- 这种方式需要注意:
- 子组件只有一个插槽;
- 当有多个插槽时,父组件将不能再添加
template
标签,否则会报错
- 当子组件有多个插槽时,父组件就只能使用上面两种方式。
插槽这种传递参数的方式在使用第三方库时是非常常用的一种功能。
__END__