在vue中有个slot插槽的东西,很多同学不知道这玩意到底是干啥的。
插槽么,突出的是一个插字,哦。。。可别想歪了,咱思想都纯洁一点哈~~
那具体怎么插呢?就是从父亲插到孩子。
比如父亲定义一个header和footer的样式,希望给孩子拿过去使用,这样孩子就不用再定义一遍了。
<Child>
<header>这是父亲给孩子留下的东西-header</header>
<footer>这是父亲给孩子留下的东西-footer</footer>
</Child>
插槽分了三种类型,分别是匿名插槽、具名插槽和作用域插槽,下面一一介绍之。
匿名插槽
匿名插槽,就是父亲定义了一些html标签,孩子拿过去直接用就行。
粗暴的理解就是:父亲所有的东西都给孩子。
父组件:
<template>
<div class="hello">
<!--匿名插槽-->
<Child1>
<h1>这是父亲留下的东西</h1>
</Child1>
</div>
</template>
<script>
import Child1 from './child1'
export default {
name: 'HelloWorld',
components:{Child1},
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
子组件child1.vue:
<template>
<div>
<slot></slot>
{{text}}
</div>
</template>
<script>
export default {
name: 'Child',
data () {
return {
text: '我是孩子-1'
}
}
}
</script>
执行结果:
1.jpg
具名插槽
具名插槽就是父亲定义了一些html标签,会指定具体怎么使用。
粗暴的理解就是:父亲只给孩子一部分东西。
父组件:
<template>
<div class="hello">
<!--具名插槽-->
<Child>
<h2 slot="header">这是父亲留下的header信息</h2>
<div>这是父亲保留的内容</div>
<h2 slot="footer">这是父亲留下的footer信息</h2>
</Child>
</div>
</template>
<script>
import Child from './child'
export default {
name: 'HelloWorld',
components:{Child},
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
子组件child.vue:
<template>
<div>
<slot name="header"></slot>
{{text}}
<slot name="footer"></slot>
</div>
</template>
<script>
export default {
name: 'Child',
data () {
return {
text: '我是孩子'
}
}
}
</script>
执行结果:
2.jpg
作用域插槽
顾名思义,就是父亲定义了一个作用域,并且定义了这个作用域的逻辑,然后孩子拿过去具体实现它。
父组件:
<template>
<div class="hello">
<!--作用域插槽-->
<Child2>
<!--myscope是一个作用域标识-->
<template slot-scope="myscope">
<!--子组件要实现的是作用域下的item这个字段-->
<span>{{myscope.item}}</span>
</template>
</Child2>
</div>
</template>
<script>
import Child2 from './child2'
export default {
name: 'HelloWorld',
components:{Child2},
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
子组件child2.vue:
<template>
<div>
<ul>
<li v-for="(v,k) in items" :key="k">
<!--item字段要赋值实现-->
<slot :item="k"></slot>:
{{v}}
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Child2',
data () {
return {
items:['Webkit','Gecko','Trident','Blink']
}
}
}
</script>
执行结果:
3.jpg
插槽应用场景
这里重点说一下作用域插槽。看个场景,比如有如下这一个列表页:
tb.jpg列表项有图片、标题和描述,其中标红的描述部分出现了不一致。
这个功能我们可以划分为父组件、列表项组件(list.vue)和描述组件(comment.vue)三部分。
我们在父组件for循环列表项组件,点击描述信息会跳到商品详情。
传统的做法是从父组件传递数据和跳转事件给list.vue,然后list.vue再将描述的文字信息和跳转事件继续传递到comment.vue,最后由comment.vue执行跳转。
这样设计不太直观,而且有一定的耦合。因为跳转事件是发生在comment.vue的,凭什么让list.vue参与进来呢?
好的设计是划分好组件各自的职责,组件只做自己应该干的事情。
我们可以用slot优雅的解决这个问题。
父组件:
<template>
<div class="hello">
<ul>
<li v-for="(v,k) in dataList" :key="k">
<List :item="v">
<template slot-scope="myscope">
<!--定义myscope.row字段,放在List去实现-->
<Comment :comm="myscope.row.comment" @myclick="toDetail(myscope.row.id)"></Comment>
</template>
</List>
</li>
</ul>
</div>
</template>
<script>
import List from './list'
import Comment from './comment'
export default {
name: 'HelloWorld',
components:{List:List,Comment:Comment},
data () {
return {
dataList:[
{id:1,title:'商品1',comment:'这是商品1的描述'},
{id:2,title:'商品2',comment:'这是商品2的描述'},
{id:3,title:'商品3',comment:'这是商品3的描述'},
{id:4,title:'商品4',comment:'这是商品4的描述'}
]
}
},
methods:{
toDetail(id){
console.log('商品详情',id)
}
}
}
</script>
list.vue:
<template>
<div>
<div>
商品名称:{{item.title}}
<slot :row="item"></slot><!--实现row字段-->
</div>
</div>
</template>
<script>
export default {
name: 'List',
props:{
item:{
required:true,
}//继承父类的属性
},
data () {
return {
}
}
}
</script>
comment.vue
<template>
<div>
<h3 @click="clickComment">{{comm}}</h3>
</div>
</template>
<script>
export default{
name:'Comment',
props:{
comm:{
required:true,
}
},
methods:{
clickComment(){
this.$emit('myclick')
}
}
}
</script>
运行结果:
res.jpg
网友评论