Vue插槽v-slot用法简介

930 阅读4分钟

    每说一次再见,
    就是死去一点点。
 
       --《漫长的告别》雷蒙钱德勒

什么是插槽

在 Vue 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope这两个目前已被废弃但未被移除且仍在文档中的attribute。

插槽,也就是slot,是组件的一块HTML模板,这块模板显示不显示、以及怎样显示由父组件来决定。 实际上,一个slot最核心的两个问题在这里就点出来了,是显示不显示和怎样显示。

由于插槽是一块模板,所以对于任何一个组件,从模板种类的角度来区分的话,可以分为非插槽模板和插槽模板两大类:

  • 非插槽模板指的是html模板,比如div、span、ul、table这些,非插槽模板的显示与隐藏以及怎样显示由组件自身控制;

  • 插槽模板是slot,它是一个空壳子,因为它的显示与隐藏以及最后用什么样的html模板显示由父组件控制。但是插槽显示的位置却由子组件自身决定,slot写在组件template的什么位置,父组件传过来的模板将来就显示在什么位置。

子组件决定位置,父组件决定内容

插槽的分类

插槽一共就三大类:

  1. 匿名插槽(也叫默认插槽): 没有命名,有且只有一个

  2. 具名插槽: 相对匿名插槽组件slot标签带name命名的

  3. 作用域插槽: 子组件内数据可以被父页面拿到(解决了数据只能从父页面传递给子组件)

匿名插槽(默认插槽)

说明:匿名插糟只需要一个,示例如下:

  • 子组件(SlotChild.vue):
 <button type="submit">
    <slot>Submit</slot>
 </button>

可在子组件的slot标签中设置一个默认值,当父组件不提供值时,默认值会进行填充。

  • 父页面:
 <SlotChild> 
    Save
 </SlotChild>  

渲染结果

<button type="submit">
  Save
</button>

总结,在匿名插槽中,父组件内无需使用template包裹内容

具名插槽(name)

说明:和匿名插槽比较,就是必须起名对应,可以有多个具名插槽,且具名插槽可以在一个组件中出现N次,出现在不同的位置,实例如下:

  • 子页面
  <div class="container">
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot></slot>
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>

一个不带 name 的 出口会带有隐含的名字“default”

  • 父组件
<SlotChild> 
 <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</SlotChild> 

现在<template> 元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有 v-slot 的 <template>中的内容都会被视为默认插槽的内容。

  • 渲染结果
<div class="container">
  <header>
    <h1>Here might be a page title</h1>
  </header>
  <main>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </main>
  <footer>
    <p>Here's some contact info</p>
  </footer>
</div>

注意:

  • 可使用动态插槽名:v-slot:[dynamicSlotName]

  • 具名插槽可缩写:v-slot:header 可以被重写为 #header

作用域插槽

说明:父组件可接取子组件传递过来的值,例如:user="user" :text="text"类似属性的数据。实际上,对比前面两种插槽,我们可以叫它带数据的插槽,示例如下:

  • 子组件
  <span>
    <slot v-bind:user="user" v-bind:text="text">
      {{ user.lastName }}
    </slot>
  </span>
  • 父组件
  <SlotChild>
    <template v-slot:default="slotProps">
      <p>{{ slotProps.user.firstName }}</p>
      <p>{{ slotProps.text }}</p>
    </template>
  </SlotChild>

数据传递过程如下图所示:

作用域插槽传值

总结,在使用上v-slot时,只需要考虑好下面两点即可:

  1. 是否需要命名(匿名插槽,具名插槽)

  2. 父页面是否需要取存在子页面的数据(作用域插槽)

参考文章: Vue 作用域插槽