不管何时何地,永远保持热爱,永远积极向上!!!
【21.Vue中的插槽slot
】
-
问题:插槽(slot)是什么?兄弟们也可以点这里去看这位兄弟的博客,写的比我详细!!!
- 【理解1】:插槽就是子组件中的提供给父组件使用的一个占位符,用
<slot></slot>
表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>
标签。简单理解就是子组件中留下个“坑”,父组件可以使用指定内容来补“坑”。 - 【理解2】:插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。插槽显不显示、怎样显示是由父组件来控制的;而插槽在哪里显示就由子组件来进行控制。
- 【理解1】:插槽就是子组件中的提供给父组件使用的一个占位符,用
-
问题:三种插槽(slot):
-
1、默认插槽
<slot></slot>
-
2、具名插槽
<slot name="名称"></slot>
-
3、作用域插槽
<slot :自定义 name = data 中的属性对象></slot>
-
1.默认插槽slot
- 【父组件:App;子组件:Category】
- 在子组件:Category中定义一个默认插槽。
<template>
<div class="about">
<h1>这里是子组件Category</h1>
<!-- 定义一个默认插槽【坑】 -->
<slot></slot>
</div>
</template>
- 在App父组件中的子组件
<category>--这里东西放入子组件的插槽中--</category>
。
<template>
<div class="container">
<h1>这里是父组件</h1>
<category title="美食">
<img src="http://rwt9uxba6.hd-bkt.clouddn.com/9999.png" />
</category>
</div>
</template>
- 但是,如果在子组件:Category中定义多个默认插槽【比如:两个默认插槽】。
那么,就会把要放入插槽中的东西复制几份【比如:两个默认插槽就复制两份】
<template>
<div class="about">
<h1>这里是子组件Category</h1>
<!-- 定义一个默认插槽【坑】 -->
<slot></slot>
<slot></slot>
</div>
</template>
- 自己的例子展示:
上面案例完整代码:
main.js
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入vue-resource插件
// import vueResource from 'vue-resource';
//关闭Vue的生产提示
Vue.config.productionTip = false
//使用插件
// Vue.use(vueResource)
//创建vm
new Vue({
el:'#app',
render: h => h(App),
// 生命周期钩子beforeCreate中模板未解析,且this是vm
beforeCreate() {
// this:指的是vm
Vue.prototype.$bus = this //安装全局事件总线$bus
}
})
App.vue
<template>
<div class="container">
<category title="美食">
<img src="http://rwt9uxba6.hd-bkt.clouddn.com/9999.png" />
</category>
<category title="游戏">
<ul>
<li v-for="(g, index) in games" :key="index">{{ g }}</li>
</ul>
</category>
<category title="电影">
<video
src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
></video>
</category>
</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>
Category.vue
<template>
<div class="category">
<h3>{{ title }}分类</h3>
<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
<slot>我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
</div>
</template>
<script>
export default {
name: 'Category',
// 父组件给子组件传递数据:props
props: ['title'],
};
</script>
<style scoped>
.category {
background-color: aquamarine;
width: 200px;
height: 300px;
}
h3{
background-color: orange;
/* 为文本或img标签等一些内联对象(或与之类似的元素)的居中。 */
text-align: center;
}
img {
/* 占父元素的比例 */
width: 100%;
}
video {
/* 占父元素的比例 */
width: 100%;
}
</style>
2.具名插槽slot
- 什么是具名插槽?
其实就是在子组件中定义插槽时,给对应的插槽分别起个名字,方便后边插入父组件将根据name来填充对应的内容。
<slot name="one"></slot> <slot name="two"></slot>
-
【父组件:App;子组件:Category】
-
在子组件:Category中定义两个具名插槽。
<template>
<div class="about">
<h1>T这里是子组件Category</h1>
<!-- 给插槽加了个name属性,就是所谓的具名插槽了 -->
<slot name="one"></slot>
<slot name="two"></slot>
</div>
</template>
- 在App父组件中的子组件
<category>【这里东西放入子组件的插槽中,有插槽名的一一对应放入】</category>
。
<category title="美食">
<template slot="one">
<p>one插槽</p>
</template>
<template slot="two">
two插槽
</template>
</category>
- 【注意】:要放入具名插槽的结构,最好用
</template slot="插槽名">
包裹起来,好处是:</template>
不渲染真实DOM,结构少了一层,并且还可以用这种写法【v-slot:插槽名】:<template v-slot:插槽名>
。
具名插槽案例效果展示:
具名插槽案例的完整代码:
<video controls></video>
:video标签里面的controls属性是控制视频播放的按钮 。
父组件App.vue
<template>
<div class="container">
<category title="美食">
<img slot="center" src="http://rwt9uxba6.hd-bkt.clouddn.com/9999.png" />
<a slot="footer" href="http://www.atguigu.com">更多美食</a>
</category>
<category title="游戏">
<ul slot="center">
<li v-for="(g, index) in games" :key="index">{{ g }}</li>
</ul>
<div class="footer" slot="footer">
<a href="http://www.atguigu.com">单机游戏</a>
<a href="http://www.atguigu.com">网络游戏</a>
</div>
</category>
<category title="电影">
<!-- controls:控制视频的播放按钮 -->
<video
controls
slot="center"
src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
>
</video>
<template slot="footer">
<div class="footer">
<a href="http://www.atguigu.com">经典</a>
<a href="http://www.atguigu.com">热门</a>
<a href="http://www.atguigu.com">推荐</a>
</div>
<h4>欢迎前来观影</h4>
</template>
</category>
</div>
</template>
<script>
import Category from './components/Category';
export default {
name: 'App',
components: { Category },
data() {
return {
foods: ['火锅', '烧烤', '小龙虾', '牛排'],
games: ['红色警戒', '穿越火线', '劲舞团', '超级玛丽'],
films: [
'《教父》',
'《拆弹专家》',
'《你好,李焕英》',
'《尚硅谷》',
],
};
},
};
</script>
<style scoped>
.container ,.footer{
/* 弹性布局 */
display: flex;
/* 弹性项目平均分布在该行上,两边留有一半的间隔空间。 */
justify-content: space-around;
}
h4{
/* 为文本或img标签等一些内联对象(或与之类似的元素)的居中。 */
text-align: center;
}
</style>
子组件Category.vue
<template>
<div class="category">
<h3>{{ title }}分类</h3>
<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
<slot name="center">我是一些默认值,当使用者没有传递具体结构时,我会出现1</slot>
<slot name="footer">我是一些默认值,当使用者没有传递具体结构时,我会出现2</slot>
</div>
</template>
<script>
export default {
name: 'Category',
// 父组件给子组件传递数据:props
props: ['title'],
};
</script>
<style scoped>
.category {
background-color: aquamarine;
width: 200px;
height: 300px;
}
h3{
background-color: orange;
/* 为文本或img标签等一些内联对象(或与之类似的元素)的居中。 */
text-align: center;
}
img {
/* 占父元素的比例 */
width: 100%;
}
video {
/* 占父元素的比例 */
width: 100%;
}
</style>
3.作用域插槽【v-slot指令】
- 什么是作用域插槽?【也可以点击此处去官方文档看】
作用域插槽的主要作用是在书写插槽内容时可以获取到插槽作用域的值。
作用域插槽就是实现在子组件自行决定自己要显示什么内容。 并且,能够让要放入插槽的内容能够访问子组件中才有的数据。【一种子给父通信的方法】
可以让要放入模板中的数据一样,但是HTML结构不一样:如下面的案例中的三个小卡片放入的data一样,但是样式不一样。【一个无序、一个有序且字体有颜色、还有一个应用了后h4字体样式】
要放入插槽的内容指的是:
父组件中<category>里面的包裹的东西
<category title="美食"> <template v-slot="childrenDate"> <p>one插槽</p> </template> <div scope="childrenDate"> <p>one插槽</p> </div> </category>
- 此处的
v-slot指令
可以替换成scope
和slot-scope
- 【注意 】
v-slot
只能添加在<template>
上- 【模板】子组件Category要传给父组件的data:
<slot :自定义的name=子组件data中的属性或对象></slot>
-
<template>
元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有v-slot
的<template>
中的内容都会被视为默认插槽的内容。 -
【例子:Category.vue】子组件Category要传给父组件的data:
<slot :childrenDate=games></slot>
data() { return { games: ['红色警戒', '穿越火线', '劲舞团', '超级玛丽'], }; },
- 【例子:App.vue】父组件App要接收子组件传过来的data:
<category title="游戏"> <template scope="haha"> <ul> <li v-for="(g,index) in haha.childrenDate" :key="index">{{g}}</li> </ul> </template> </category>
补充一个点:
- 【例子:Category.vue】子组件Category要传给父组件的data有两个参数:
<slot :dataOfCategory="games" :Msg="nihao"></slot>
data() { return { games: ['红色警戒', '穿越火线', '劲舞团', '超级玛丽'], nihao:'我是伍六七,我喜欢梅小姐!', }; },
- 【例子:App.vue】父组件App要接收子组件传过来的数据
haha
,我们看一下它的到底是个什么玩意???
<category title="游戏"> <template scope="haha"> <ul> <li v-for="(g, index) in haha.dataOfCategory" :key="index"> {{ g }} </li> </ul> <button @click="CategoryDate(haha)"> <h2>点击查看子组件传过来的数据</h2> </button> </template> </category>
methods: { CategoryDate(haha) { console.log(haha); }, },
结果展示:
有点看不清,那就月下观鸟:
具名插槽案例效果展示:
完整代码:
App.vue组件
<template>
<div class="container">
<!-- 让子组件展示的数据是无序的 -->
<category title="游戏">
<template scope="haha">
<ul>
<li v-for="(g, index) in haha.dataOfCategory" :key="index">
{{ g }}
</li>
</ul>
<button @click="CategoryDate(haha)">
<h2>点击查看子组件传过来的数据</h2>
</button>
</template>
</category>
<!-- 让子组件展示的数据是有序的 -->
<category title="游戏">
<!-- 对象的解构赋值 -->
<template slot-scope="{ dataOfCategory }">
<ol>
<li
style="color: orange"
v-for="(g, index) in dataOfCategory"
:key="index"
>
{{ g }}
</li>
</ol>
</template>
</category>
<category title="游戏">
<template v-slot="hello">
<h4 v-for="(g, index) in hello.dataOfCategory" :key="index">
{{ g }}
</h4>
</template>
</category>
</div>
</template>
<script>
import Category from './components/Category';
export default {
name: 'App',
components: { Category },
methods: {
CategoryDate(haha) {
console.log(haha);
},
},
};
</script>
<style scoped>
.container,
.footer {
/* 弹性布局 */
display: flex;
/* 弹性项目平均分布在该行上,两边留有一半的间隔空间。 */
justify-content: space-around;
}
h4 {
/* 为文本或img标签等一些内联对象(或与之类似的元素)的居中。 */
text-align: center;
}
button{
/* 为文本或img标签等一些内联对象(或与之类似的元素)的居中。 */
text-align: center;
background-color: blueviolet;
}
</style>
Category.vue组件
<template>
<div class="category">
<h3>{{ title }}分类</h3>
<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
<slot :dataOfCategory="games" :Msg="nihao">我是一些默认值,当使用者没有传递具体结构时,我会出现1</slot>
</div>
</template>
<script>
export default {
name: 'Category',
// 父组件给子组件传递数据:props
props: ['title'],
data() {
return {
games: ['红色警戒', '穿越火线', '劲舞团', '超级玛丽'],
nihao:'我是伍六七,我喜欢梅小姐!',
};
},
};
</script>
<style scoped>
.category {
background-color: aquamarine;
width: 200px;
height: 300px;
}
h3{
background-color: orange;
/* 为文本或img标签等一些内联对象(或与之类似的元素)的居中。 */
text-align: center;
}
img {
/* 占父元素的比例 */
width: 100%;
}
video {
/* 占父元素的比例 */
width: 100%;
}
</style>
插槽总结:
-
作用:让父组件可以向子组件指定位置插入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组件决定)
-
具体编码:【见上面的案例的代码】
-
-