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>

 

 

 

posted @ 2020-10-15 14:36  web前端煜  阅读(21837)  评论(0编辑  收藏  举报