scoped slots(作用域插槽深入理解)$scopedSlots
vue中插槽作用是什么?就是子组件写一个<slot>标签占一个坑,父组件在使用这个子组件的时候,在子组件标签中加入一些内容,这些内容将在占坑的地方出现
作用域插槽是什么?父组件通过在子组件中使用插槽填充内容的时候,可以通过slot-scope属性获取 子组件中<slot>标签 通过属性 传递过来的子组件的作用域 的值。
//parent.vue <child :data="data"> //这个scope随意起名,代表的就是子组件slot标签所有属性组成的对象 <span slot-scope="scope">{{ scope.name }}</span> </child> //child.vue <div> 子组件{{data}} <slot :name="name"></slot> </div>
想象第一个场景:一个商品列表,点击每个商品跳转到详情页知道了什么意思,以及用法,那他的应用场景是什么呢?
首先将商品卡片写成一个组件GoodsCard.vue,在GoodsList.vue中一个v-for循环商品card
<goods-card v-for="(item,index) in goodsList" @clickGoods="onGoodsClick"></goods-card>
第一个场景实现了,没啥问题,现在想象第二个场景,比如,淘宝网站上,有两组商品列表子组件只需要在点击商品的时候触发this.$emmit("clickGoods",item),将数据传给父组件进行跳转
此时GoodsList.vue就需要抽成组件了,在商品GoodsPage中v-for调用GoodsList.vue,产生多个商品列表
这样跳转详情页的话,如果还用this.$emit就需要三层传递click,card->goodsList->goodspage,那这样子组件跟业务扯上关系,显得不纯粹,这个时候就用上了作用于插槽
<el-row :gutter="20"> //columnList 存储多个商品列表 <el-col :span="12" v-for="(column, index) in columnList" :key="index"> <goods-list :goodsList="column.goodsList"> <template slot-scope="scope"> <!-- 这里只需要给GoodsCard组件传入数据,响应GoodsCard组件的onGoodsClick事件即可。 事件不必携带参数,完全符合父到子的数据流向,而不会发生子组件又给父组件反向发数据的情况 --> <goods-card @click="onGoodsClick(scope.row)"></goods-card> </template> </goods-list> </el-col> </el-row>
<el-row :gutter="20"> <el-col :span="8" v-for="(item, index) in goodsList" :key="index"> <slot :row="item"></slot> </el-col> </el-row>
GoodsList.vue应该是这样的,<slot>设置属性item,这样父组件就可以通过作用域插槽访问到点击的项,而无需触发this.$emit
知道了作用域插槽使用场景,但是这就是作用域插槽的全部吗?不是
官方提供了两个API,分别是this.$slots和this.$scopedSlots,并且官方提示:vm.$slots和vm.$scopedSlots在使用渲染函数开发一个组件时特别有用。
首先看一下这两个在使用的时候输出什么
<template> <test> <div slot="header">slot: header</div> <div slot-scope="scope">slot: {{scope}}</div> <div slot="footer">slot: footer</div> </test> </template> <script> import Test from './test.vue' export default { components: { Test } } </script>
<template> <div> <slot name="header"></slot> <slot></slot> <slot name="footer"></slot> </div> </template> <script> export default { data () { return { test: { name: 'default' } } }, mounted () { console.log(this.$slots, '$slots') console.log(this.$scopedSlots, '$scopedSlots') } } </script>
可以看出是否是$scopedSlots,就是使用插槽时是否有slot-scope特性
!!!通过控制台打印结果,明晰this.$slots和this.$scopedSlots[name](),结果是vnode,相当于<slot>作用
我们用jsx写一个例子看一下:
<script> export default { props: { data: { type: Array, default () { return [] } } }, data () { return { } }, render (h, vm) { return ( <ul> {this.data.map(item => ( <li> //传递给作用域对象 插槽内容 父级传过来的数据 {this.$scopedSlots.default(item)|| this.$slots.default || item.name} //意思就是告诉父组件你插槽内容是哪一项 </li> ))} </ul> ) } } </script>
<template> <test :data="data"> //scope就是this.$scopedSlots.default(item)传递过来的item <span slot-scope="scope">{{scope.name}} | vm.scopedSlots的使用</span> </test> </template> <script> import Test from './test.vue' export default { components: { Test }, data () { return { data: [ { name: 111 }, { name: 222 }, { name: 333 } ] } } } </script>