Vue:关于插槽的详解
Vue:关于插槽的详解。包括默认插槽的使用,具名插槽的使用,动态插槽名,作用域插槽的使用以及实战应用场景,和插槽的多层嵌套
Vue:插槽Slot
一、默认插槽
1、代码演示
通过上述代码,我们至少了解以下2点:
1.插槽里可以有默认内容,
2.默认插槽,组件的内容会全部替换到插槽中
2.父组件的数据也可以显示到子组件中(数据的作用域,后面作用域插槽会用到)
2、语法
定义插槽:<slot>插槽的默认内容</slot>
使用插槽:<组件> 内容全部替换到插槽中 </组件>
二、具名插槽
1、代码演示
具名插槽:简单理解,就是为每个
<slot>
进行命名,以进行区分。
注意:默认插槽也是有name
的,name='default'
2、语法
定义插槽:<slot name="one"></slot>
使用插槽:<template v-slot:one> <div>{{ msg }}</div> </template>
插槽简写:<template #one> <div>{{ msg }}</div> </template>
3、动态插槽名
动态插槽名:
现在定义的插槽名都是固定写死的,Vue也支持将插槽名定义为变量。
定义插槽:<slot :name="name"></slot>
使用插槽:<template #[name]> <div>动态插槽名</div> </template>
三、作用域插槽
1、渲染作用域
渲染作用域:
父级模板里的所有内容都是在父级作用域中编译的
子模板里的所有内容都是在子作用域中编译的
因此也产生了一个问题:
假设第一个场景,需要你写一个商品卡片组件,并通过循环去展示多个卡片,
并且要求能响应每个卡片上的点击事件而跳转到商品详情页,你会怎么写?
我会使用如下的处理方式,
- 首先将商品卡片写成一个组件
card.vue
,- 在
cardList.vue
中用一个v-for
来处理商品卡片列表的展示。card.vue
组件通过$emit
向父组件传递cardClick
事件,并携带商品数据,- 父组件即可在
onClick
方法中得到数据,进行业务处理,- 这样便完成了一个基本的由子到父的数据传递。
// cardList.vue
<template>
<div class="card">
<Card v-for="item in cardData" :key="item" @cardClick="onClick()"></Card>
</div>
</template>
// card.vue
<template>
<div class="div" @click="onClick()">卡片</div>
</template>
<script>
export default {
methods: {
onClick () {
this.$emit('cardClick')
}
}
}
</script>
如果再往上抽象一下呢?
比如有多个运营栏目,像淘宝首页有“有好货”,“爱逛街”这样两个栏目,每个栏目下都需要有一个商品卡片列表,那么商品卡片列表cardList.vue
就要抽成组件了。而这个包含多个运营栏目的vue组件我假设它叫finalList.vue
,在其中通过v-for
调用了cardList.vue
组件。
注意:
需求来了—>我希望把点击商品卡片的业务放在finalList.vue
中处理。要如何处理呢?
方法1:
- 商品按钮点击时,
card.vue
组件用$emit
通知cardList.vue
,cardList.vue
继续用$emit
往上抛,通知finalList.vue
finalList.vue
用事件接收处理。
这样做完全没有问题,但是显得子组件很不纯粹,跟业务都扯上关系了。
2、作用域插槽(实战应用)
那么如何优雅地解决上面的问题呢?这个时候,作用域插槽真正派上用场了。
我们先看下通过作用域插槽是如何解决上面问题的。
(1)finalList.vue
// src\views\06slot\finalList.vue
<template>
<div>
<div v-for="item in '123'" :key="item">
<div style="text-align: left;">第{{ item }}个</div>
<CardList :cardData="cardData" class="cardlist">
<template v-slot="scope">
<Card :cardObj="scope.row" @click.native="cardClick(scope.row)" class="card"></Card>
</template>
</CardList>
</div>
</div>
</template>
<script>
import Card from './card.vue'
import CardList from './cardList.vue'
export default {
components: {
Card,
CardList
},
data () {
return {
cardData: [
{ name: 'zs', age: 18 },
{ name: 'ls', age: 19 }
]
}
},
methods: {
cardClick (row) {
console.log('卡片点击了:' + row.name + '--' + row.age)
}
}
}
</script>
<style scoped>
.cardlist {
display: flex;
}
.card {
margin: 10px 20px;
}
</style>
(2)cardList.vue
// src\views\06slot\cardList.vue
<template>
<div>
<div v-for="(item, index) in cardData" :key="index">
<slot :row="item"></slot>
</div>
</div>
</template>
<script>
export default {
props: {
cardData: {
type: Array
}
}
}
</script>
<style scoped>
</style>
(3)card.vue
// src\views\06slot\card.vue
<template>
<div class="div">
<div>{{ cardObj.name }}</div>
<div>{{ cardObj.age }}</div>
</div>
</template>
<script>
export default {
props: {
cardObj: {
type: Object,
default: () => { }
}
}
}
</script>
<style scoped>
.div {
width: 100px;
height: 100px;
background-color: pink;
}
</style>
(4)最终效果
小结
关于作用域插槽:
简单理解:作用域插槽就是简化
子组件通过$emit向父组件多层传递
数据的另一种表现
适用的场景:至少是包含三级以上的组件层级,是一种优秀的组件化方案!
3、简单应用demo
- 父组件访问子组件的数据:
- 父组件获取组件slot属性:
v-slot="slotProps"
, - 子组件将数据绑定到动态属性中:
<slot :item="item"></slot>
- 父组件获取组件slot属性:
- 按照父组件期望的形式进行数据展示:
- 子组件中定义slot插槽:
<slot :item="item" :index="index"></slot>
- 父组件通过插槽的方式替换子组件的插槽内容
- 子组件中定义slot插槽:
四、插槽的多层嵌套
1、需求
A、B、C三个组件,A组件插槽的内容传给B组件,B组件再传递给C组件。
2、代码演示
// src\views\06slot\parent.vue
<template>
<div>
<Children1>
<template v-slot:one>
<div>根节点信息</div>
</template>
</Children1>
</div>
</template>
// src\views\06slot\children1.vue
<template>
<div>
<div>children1</div>
<Children2>
<slot name="one" slot="two"></slot>
</Children2>
</div>
</template>
// src\views\06slot\children2.vue
<template>
<div>
<div>children2</div>
<slot name="two"></slot>
</div>
</template>
3、代码效果
4、核心点
- A组件用
v-slot:one
将内容传递给B组件 - B组件用
name="one"
接收插槽的内容,并通过slot="two"
将内容传递个C组件。即:<slot name="one" slot="two"></slot>
- C组件用
<slot name="two"></slot>
接收A组件的内容
更多推荐
所有评论(0)