slot

# 为什么使用 slot

  • slot 翻译为 插槽

  • <mark>插槽的目的是让我们原有的设备具备更多的扩展性(类java接口?)</mark>

功能和实现分离 - 复用+解耦

栗子:移动网站中的导航栏。

  • 移动开发中,几乎每个页面都有导航栏。
  • 导航栏我们必然会封装成一个插件,比如nav-bar组件。
  • 一旦有了这个组件,我们就可以在多个页面中复用了。

# 如何封装这类组件呢?slot

它们也很多=区别==,但是也有很多<mark>共性</mark>。

  • 如果,我们每一个单独去封装一个组件,显然不合适:比如每个页面都返回,这部分内容我们就要重复去封装。
  • 但是,如果我们封装成一个,好像也不合理:有些左侧是菜单,有些是返回,有些中间是搜索,有些是文字,等等。

如何封装合适呢?<mark>抽取共性,保留不同</mark>。 求同存异

  • 最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽。
  • 一旦我们预留了插槽,就可以让使用者根据自己的需求,决定插槽中插入什么内容。
  • 是搜索框,还是文字,还是菜单。由调用者自己来决定。

这就是为什么我们要学习组件中的插槽slot的原因。

# slot基本使用

在模板里面添加 <slot></slot> 标签

父组件调用的时候,在子组件标签内添加内容(如下)

<body>

  <!-- 2.父组件模板 -->
  <div id='app'>
    <cpn><button>按钮</button></cpn>
    <cpn>
      <font color='red'>哈哈哈</font>
    </cpn>
    <cpn><a href="www.baidu.com">百度一下</a></cpn>
    <cpn>
      <p>Eveniet perspiciatis officia voluptate. Temporibus aut ut. Voluptas quasi corporis et assumenda voluptatum.
        Nisi rerum accusantium repudiandae illo. Ut dolor nemo velit veniam sunt exercitationem et eum ipsam.

        Eligendi a repudiandae voluptatum quae consequatur. Quo vel esse cum doloremque voluptatem. Reiciendis est ut
        blanditiis impedit soluta est dolorem consequatur. Quia delectus sint ut illum exercitationem unde et. Nostrum
        adipisci eveniet laudantium modi eligendi laudantium tenetur quo.

        Ipsum sed explicabo culpa labore veritatis et architecto incidunt ea. Voluptas harum et quo ut est adipisci
        itaque ipsum similique. Cumque magnam animi laborum perspiciatis non totam non culpa. Asperiores perspiciatis
        voluptatibus dolorem illo sunt qui dolore nobis.
      </p>
    </cpn>
  </div>

  <!-- 1.子组件模板 -->
  <template id="cpn">
    <div>
      <h2>我是组件</h2>
      <p>下面是插槽</p>
      <slot></slot>
    </div>
  </template>

  <script src="../dist/vue.js"></script>
  <script> const cpn = { template: '#cpn', } const app = new Vue({ el: '#app', data: {}, components: { cpn: cpn } }) </script>
</body>

# slot 默认值

可以在 <slot></slot> 中添加内容,表示默认值

当用子组件时候,没有在 slot 中添加东西,则用默认值(如下图)

<body>

  <!-- 2.父组件模板 -->
  <div id='app'>
    <!-- 不写东西,则使用默认值 -->
    <cpn></cpn>
    <cpn></cpn>
    <cpn><a href="www.baidu.com">百度一下</a></cpn>
    <cpn>
      <p>Eveniet perspiciatis officia voluptate. Temporibus aut ut. Voluptas quasi corporis et assumenda voluptatum.
        Nisi rerum accusantium repudiandae illo. Ut dolor nemo velit veniam sunt exercitationem et eum ipsam.

        Eligendi a repudiandae voluptatum quae consequatur. Quo vel esse cum doloremque voluptatem. Reiciendis est ut
        blanditiis impedit soluta est dolorem consequatur. Quia delectus sint ut illum exercitationem unde et. Nostrum
        adipisci eveniet laudantium modi eligendi laudantium tenetur quo.

        Ipsum sed explicabo culpa labore veritatis et architecto incidunt ea. Voluptas harum et quo ut est adipisci
        itaque ipsum similique. Cumque magnam animi laborum perspiciatis non totam non culpa. Asperiores perspiciatis
        voluptatibus dolorem illo sunt qui dolore nobis.
      </p>
    </cpn>
  </div>

  <!-- 1.子组件模板 -->
  <template id="cpn">
    <div>
      <h2>我是组件</h2>
      <p>下面是插槽</p>
      <slot>
        <!-- 添加默认值 -->
        <button>默认按钮</button>
      </slot>
    </div>
  </template>

  <script src="../dist/vue.js"></script>
  <script> const cpn = { template: '#cpn', } const app = new Vue({ el: '#app', data: {}, components: { cpn: cpn } }) </script>
</body>

# 具名插槽 name

<mark>子组件的插槽可能并非是一个。</mark>
比如我们封装一个导航栏的子组件,可能就需要三个插槽,分别代表左边、中间、右边。
那么,外面在给插槽插入内容时,如何区分插入的是哪一个呢?
这个时候,我们就需要给插槽起一个名字

  • 如何使用具名插槽呢?
    非常简单,只要给slot元素一个name属性即可
    <slot name='myslot'></slot>

我们来给出一个案例:

<body>

  <!-- 2.父组件模板 -->
  <div id='app'>
    <cpn><a href="www.baidu.com" slot="left">百度一下</a></cpn>
    <cpn><a href="www.baidu.com" slot="center">百度一下</a></cpn>
    <cpn><a href="www.baidu.com" slot="right">百度一下</a></cpn>
  </div>

  <!-- 1.子组件模板 -->
  <template id="cpn">
    <div>
      <slot name='left'>左边</slot>
      <slot name='center'>中间</slot>
      <slot name='right'>右边</slot>
    </div>
  </template>

  <script src="../dist/vue.js"></script>
  <script> const cpn = { template: '#cpn', } const app = new Vue({ el: '#app', data: {}, components: { cpn: cpn } }) </script>
</body>

这里我们先不对导航组件做非常复杂的封装,先了解具名插槽的用法。

# 作用域插槽(2.5以前:slot-scope)【废弃】

需求:<mark>父组件替换插槽的标签,但是内容由子组件来提供。</mark>

例子:
.
子组件中包括一组数据,比如:pLanguages: [‘JavaScript’, ‘Python’, ‘Swift’, ‘Go’, ‘C++’]
.
需要在多个界面进行展示:

  • 某些界面是以水平方向一一展示的,
  • 某些界面是以列表形式展示的,
  • 某些界面直接展示一个数组

.
内容在子组件,希望父组件告诉我们如何展示,怎么办呢?

利用 slot 作用域插槽就可以了

<body>

  <!-- 2.父组件模板 -->
  <div id='app'>
    <!--默认样式-->
    <cpn></cpn>
    <cpn>
      <!-- 2.5以下,必须使用template标签。以上的可以省略 2.6以上,已废除slot、slot-scope -->
      <template slot-scope='slot'>
        <span v-for='item in slot.data'>{{item}} - </span>
      </template>
    </cpn>
    <cpn>
      <!-- 2.5以下,必须使用template标签。以上的可以省略 2.6以上,已废除slot、slot-scope -->
      <template slot-scope='slot'>
        <span>{{slot.data.join(' * ')}}</span>
      </template>
    </cpn>
  </div>

  <!-- 1.子组件模板 -->
  <template id="cpn">
    <div>
      <slot :data='pLanguages'>
        <ul>
          <li v-for="item in pLanguages">{{item}}</li>
        </ul>
      </slot>
    </div>
  </template>

  <script src="../dist/vue.js"></script>
  <script> const cpn = { template: '#cpn', data() { return { pLanguages: ['JavaScript', 'Python', 'Swift', 'Go', 'C++'] } } } const app = new Vue({ el: '#app', components: { cpn: cpn } }) </script>
</body>

# 作用域插槽(2.6版后:v-slot)

  • 官方 插槽 相关 API
  • 官网废弃 slot 的 说明

  • 【由来】v-slot 完整的由来参见这份 RFC

《vue - 作用域插槽 - 案例 - v-slot (2.6后)》 - https://blog.csdn.net/LawssssCat/article/details/104575116