VUE SLOT - 插槽

Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口。

2.6.0 更新后的语法

// 基础用法
<button type="submit">
  <slot></slot>
</button>
// 插槽默认内容-Submit
<button type="submit">
  <slot>Submit</slot>
</button>

具名插槽

// 不带 name 的 <slot> 出口会带有隐含的名字“default”
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>
// 向具名插槽提供内容
<base-layout>
  <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>
</base-layout>
// 现在 <template> 元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容

注意 v-slot 只能添加在 <template> 上 (只有一种例外情况:独占默认插槽的缩写语法)

作用域插槽

用于子级作用域向父级作用域传值

// 子级:绑定在 <slot> 元素上的 attribute 被称为插槽 prop
<span>
  <slot v-bind:user="user">
    
  </slot>
</span>
// 父级作用域中,可以使用带值的 v-slot 来定义提供的插槽 prop 的名字:
<current-user>
  <template v-slot:default="slotProps">
    
  </template>
</current-user>

独占默认插槽的缩写语法

在上述情况下,当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot 直接用在组件上

<current-user v-slot:default="slotProps">
  
</current-user>

注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确。只要出现多个插槽,请始终为所有的插槽使用完整的基于 <template> 的语法:

<current-user>
  <template v-slot:default="slotProps">
    
  </template>

  <template v-slot:other="otherSlotProps">
    ...
  </template>
</current-user>

解构插槽 Prop

<current-user v-slot="{ user }">
  
</current-user>
// 将 user 重命名为 person:
<current-user v-slot="{ user: person }">
  
</current-user>
// 后备内容,用于插槽 prop 是 undefined 的情形:
<current-user v-slot="{ user = { firstName: 'Guest' } }">
  
</current-user>

具名插槽的缩写

v-slot: 等价于 #,例如 v-slot:header 可以被重写为 #header,该缩写只在其有参数的时候才可用。这意味着以下语法是无效的:

<!-- 这样会触发一个警告 -->
<current-user #="{ user }">
  
</current-user>
// 如果你希望使用缩写的话,你必须始终以明确插槽名取而代之:
<current-user #default="{ user }">
  
</current-user>

自 2.6.0 起被废弃的语法

<base-layout>
  <template 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 slot="footer">
    <p>Here's some contact info</p>
  </template>
</base-layout>

<slot-example>
  <template slot-scope="slotProps">
    
  </template>
</slot-example>

透传

// 组件
<template>
    <el-button
        v-bind="customizedAttrs"
        v-on="$listeners"
    >
        <slot />
    </el-button>
</template>

<script>
export default {
    name: "MyButton",inheritAttrs:false,
    props: {
        size: {
            type: String,
            default: "medium",
        },
    },
    computed: {
        customizedAttrs() {
            return {
                size: "medium",
                // 支持传过来的size覆盖默认的size
                ...this.$attrs,
            };
        },
    },
};
</script>
// 使用
<template>
    <my-button
        type="success"
        round
        autofocus
        @click="handleClick"
    />
</template>