十五、插槽 slot
总结在最后,这里先一步步说明插槽到底是个啥
1、先正常实现一个效果
1、效果图
2、项目结构
3、CODE
1、App.vue
<template>
<div class="container">
<Category title="美食" :listData="foods"/>
<Category title="游戏" :listData="games"/>
<Category title="电影" :listData="films"/>
</div>
</template>
<script>
import Category from './components/Category'
export default {
name:'App',
components:{Category},
data() {
return {
foods:['清蒸排骨', '红烧排骨', '醋溜排骨', '爆炒排骨'],
games:['沙漠冲突', '草原冲突', '空中冲突', '海上冲突'],
films:['《莫欺少年穷》', '《莫欺中年穷》', '《莫欺老年穷》', '《谁特么买小米》']
}
},
}
</script>
<style scoped>
.container{
display: flex;
justify-content: space-around;
}
</style>
2、Category.vue
<template>
<div class="category">
<h3>{{title}}分类</h3>
<ul>
<li v-for="(item,index) in listData" :key="index">{{item}}</li>
</ul>
</div>
</template>
<script>
export default {
name:'Category',
props:['title', 'listData']
}
</script>
<style scoped>
.category{
background-color: skyblue;
width: 200px;
height: 300px;
}
h3{
text-align: center;
background-color: orange;
}
</style>
2、改需求了!(默认插槽)
此时一位帅气的项目经理屁颠屁颠的跑过来了,说:“小白啊,美食客户加钱了,让咱们把他们的视频挂上去,电影客户也加钱了,但是没美食客户给的多,那就把电影海报挂上去就得了,游戏客户没联系上,八成是玩疯了,就不管那栏就行了。”
1、效果图
2、思考
结构已经写好了,我实在是懒得改,反正变化不大,就是展示的内容变了,有没有一种写法可以让我把展示的内容像传数据一样传给组件让它展示呢?
Vue早就想到了本帅会遇到这种问题,人家早就准备好了 slot (插槽)!没错!就是字面意思!
组件内写一个插槽标签,使用组件时组件标签内的东西就是你要插到插槽的对象
值得注意的是你要插到插槽的对象是在使用这个组件的页面上解析完了插到组件插槽上的
3、CODE
1、App.vue
<template>
<div class="container">
<Category title="美食" >
<!-- 地址超长,此处省略 -->
<video controls src="https://..."></video>
</Category>
<Category title="游戏" >
<ul>
<li v-for="(g,index) in games" :key="index">{{g}}</li>
</ul>
</Category>
<Category title="电影">
<img src="./assets/imgs/开学.png" alt="">
</Category>
</div>
</template>
2、Category.vue
<template>
<div class="category">
<h3>{{title}}分类</h3>
<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
<slot>我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
</div>
</template>
3、又改需求了!(具名插槽)
此时那位帅气的项目经理又屁颠屁颠的跑过来了,说:“小白啊,美食和电影客户又加钱了,下面还得加上一些其他展示信息,游戏客户就抠搜的。”
1、效果图
2、思考
甭思考了,就是要用多个插槽了!Vue预判了吗?嗯,预判了!具名插槽!
没错,就是字面意思!拥有 name (名字)的插槽,这样多写几个不就能区分了吗?
这回客户随便加钱,想插几个插几个,想插啥插啥,想怎么插就怎么插,谁会跟钱不去呢
3、CODE
1、App.vue
<template>
<div class="container">
<Category title="美食" >
<!-- 你要通过slot属性告诉vm,爹这个video放source插槽 -->
<video slot="source" controls src="https://..."></video>
<!-- 你要通过slot属性告诉vm,爹这个a是加了钱的,要放addMoney插槽 -->
<a slot="addMoney" href="https://blog.csdn.net/qq_30769437?spm=1011.2415.3001.5343">》》跟我来,美不胜收!</a>
<!--可以随便插,想插几个插几个,想插啥插啥,想怎么插就怎么插 -->
<!-- <a slot="addMoney" href="https://...">》》跟我来,美不胜收!</a>
<a slot="addMoney" href="https://xxx">》》跟我来,美不胜收!</a>
<a slot="addMoney" href="https://---">》》跟我来,美不胜收!</a> -->
</Category>
<Category title="游戏" >
<ul slot="source">
<li v-for="(g,index) in games" :key="index">{{g}}</li>
</ul>
</Category>
<Category title="电影">
<img slot="source" src="./assets/imgs/开学.png" alt="">
<!-- 如果多个同级Dom插同一个插槽可用标签括起来,只写一遍插槽名 -->
<!-- 当然最好选择<template>标签,可以省一层Dom结构,还能使用<template>专用的插槽简写形式 -->
<template v-slot:addMoney>
<div class="center">
<a slot="addMoney" href="https://...">上新</a>
<a slot="addMoney" href="https://xxx">热门</a>
<a slot="addMoney" href="https://---">经典</a>
</div>
<h4>周末影院,不见不散</h4>
</template>
</Category>
</div>
</template>
2、Category.vue
<template>
<div class="category">
<h3>{{title}}分类</h3>
<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
<slot name="source">我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
<br/><br/>
<slot name="addMoney">抠搜的</slot>
</div>
</template>
4、Result
4、又双叒叕改需求了!(作用域插槽)
此时那位帅气的项目经理又双叒叕屁颠屁颠的跑过来了,说:“小白啊,美食和电影客户撤资跑了,就剩游戏客户一家了,那三个栏全挂游戏吧,最后一个金主可得留住啊。”
1、思考
数据在插槽所在的组件上,使用插槽组件的组件怎么获取插槽组件的数据呢?没错就是作用域插槽
2、CODE
1、App.vue
<template>
<div class="container">
<Category title="游戏" >
<!-- 此时必须使用<template>标签!!! -->
<!-- 在<template>上用 scope 获得插槽传过来的数据对象 -->
<!-- 插槽传过来的所有数据都放在data对象里了 -->
<template scope="data">
<ul slot="source">
<li v-for="(g,index) in data.games" :key="index">{{g}}</li>
</ul>
</template>
</Category>
<Category title="游戏" >
<!-- 阔以用ES6解构省掉key -->
<template scope="{games, someElse}">
<ol slot="source">
<li v-for="(g,index) in games" :key="index">{{g}}</li>
</ol>
<h4>{{someElse}}</h4>
</template>
</Category>
<Category title="游戏" >
<!-- 还可以用新的API:slot-scope 获取插槽传过来的数据对象 -->
<template slot-scope="{games}">
<h4 v-for="(g,index) in games" :key="index">{{g}}</h4>
</template>
</Category>
</div>
</template>
<script>
import Category from './components/Category'
export default {
name:'App',
components:{Category}
}
</script>
2、Category.vue
<template>
<div class="category">
<h3>{{title}}分类</h3>
<!-- 将数据传给插槽的使用者 -->
<slot :games="games" someElse="精彩更多!">我是一些默认值...</slot>
</div>
</template>
<script>
export default {
name:'Category',
props:['title'],
data() {
return {
games:['沙漠冲突', '草原冲突', '空中冲突', '海上冲突']
}
}
}
</script>
3、Result
5、插槽 slot总结
-
作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式
- **适用于 父组件 ===> 子组件 **
-
分类:默认插槽、具名插槽、作用域插槽
-
使用方式:
-
默认插槽:
父组件中: <Category> <div>html结构1</div> </Category> 子组件中: <template> <div> <!-- 定义插槽 --> <slot>插槽默认内容...</slot> </div> </template>
-
具名插槽:
父组件中: <Category> <template slot="center"> <div>html结构1</div> </template> <template v-slot:footer> <div>html结构2</div> </template> </Category> 子组件中: <template> <div> <!-- 定义插槽 --> <slot name="center">插槽默认内容...</slot> <slot name="footer">插槽默认内容...</slot> </div> </template>
-
作用域插槽:
-
理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)
-
具体编码:
父组件中: <Category> <template scope="scopeData"> <!-- 生成的是ul列表 --> <ul> <li v-for="g in scopeData.games" :key="g">{{g}}</li> </ul> </template> </Category> <Category> <template slot-scope="scopeData"> <!-- 生成的是h4标题 --> <h4 v-for="g in scopeData.games" :key="g">{{g}}</h4> </template> </Category> 子组件中: <template> <div> <slot :games="games"></slot> </div> </template> <script> export default { name:'Category', props:['title'], //数据在子组件自身 data() { return { games:['海上冲突', '陆地冲突', '空中冲突'] } }, } </script>
-
-