前言

作用域插槽可以使vue组件更具备通用性(versatile)和可复用性(reusable)。可能唯一不足的地方是其概念有些难懂,通常我遇到不好理解的代码,便会试图将它用到实际项目中,解决之前遇到的问题。下面的正文,便是讲述我在实际项目中遇到的问题,使用scopedSlots是如何解决它。

点击链接你可以看到完整的代码

正文

app.js里,构建my-list组件,渲染shapescolors两个测试数组,接受传递的title属性,其代码如下:

Vue.component('my-list', {
  template: '#my-list',
  props: [ 'title' ]
  data() {
    return {
      shapes: [ 
       	  { name: 'Square', sides: 4 }, 
          { name: 'Hexagon', sides: 6 }, 
          { name: 'Triangle', sides: 3 }
      ],
      colors: [
	      { name: 'Yellow', hex: '#F4D03F', },
	      { name: 'Green', hex: '#229954' },
	      { name: 'Purple', hex: '#9B59B6' }
	    ]
    };
  }
});

new Vue({
  el: '#app'
});

index.html里,实现shapescolors的数据渲染,以及编写my-list组件里的template

<div id="app">
  <my-list :title="Shapes">
    <div class="list-item" v-for="item in shapes">
      <div>{{ shape.name }} <small>({{ shape.sides }} sides)</small></div>
    </div>
  </my-list>
  <my-list :title="Colors">
    <div class="list-item" v-for="color in colors">
      <div>
        <div class="swatch" :style="{ background: color.hex }"></div>
        {{ color.name }}
      </div>
    </div>
  </my-list>
</div>

<script type="text/x-template" id="my-list">
  <div class="my-list">
    <div class="title">{{ title }}</div>
    <div class="list">
      <slot></slot>
    </div>
  </div>
</script>

添加一些css,可看到渲染效果如下图所示
在这里插入图片描述
虽然实现了两组列表,但是在组件实现内部,有重复性代码<div class="list-item" v-for="item in ...">,如果我们能将其移入到my-list组件内部,而不是放到父组件上实现,那该多好!scopedSlots成功解决了该问题。

scopedSlots

它之所以被叫作"scoped" slot,那是因为虽然它的template放在父组件内渲染,但是父组件可以读取到子组件内指定的data数据
通过scopedSlots,我们改写app.js里的代码

Vue.component('my-list', {
  template: '#my-list',
  props: [ 'title', 'items' ]
});

index.html里,改动后的完整代码如下所示

<div id="app">
  <my-list title="Shapes" :items="shapes">
    <template scope="shape"> // 通过scoped,可访问到子组件内部单个数据shape
      <div>{{ shape.name }} <small>({{ shape.sides }} sides)</small></div>
    </template>
  </my-list>
  <my-list title="Colors" :items="colors">
    <template scope="color">
      <div>
        <div class="swatch" :style="{ background: color.hex }"></div>
        {{ color.name }}
      </div>
    </template>
  </my-list>   
</div>

<script type="text/x-template" id="my-list">
  <div class="my-list">
    <div class="title">{{ title }}</div>
    <div class="list">
      <div v-for="item in items">
        <slot v-bind="item"></slot>
      </div>
    </div>
  </div>
</script>

让我们先看shapes list,该模板必须包含scope属性,我们对该属性赋上一个别名shape,该别名让我们能访问作用域属性。在模板内部,我们可以像之前代码那样显示shape list。

结束语

虽然在使用scopedSlots后,仍然和以前一样有那么多的HTML标记(markup),但是它已经将公共的功能委托到组件内部,这有利于系统代码的健壮性。

有兴趣的同学,可以看看原文链接

Logo

前往低代码交流专区

更多推荐