vue slot插槽

48 阅读1分钟

使用 vue 开发的项目中常常会进行组件的封装,在封装的过程中 slot 起着非常重要的作用。

编译作用域:父级模板的内容均在父级作用域中编译,子级模板的内容均在子级作用域中编译。

1. vue 2.6.0 版本之前

子组件 child.vue:

<template>
  <div>
    <span>hello!</span>
    &nbsp;
    <!-- 默认插槽 -->
    <slot>小明</slot>
    &nbsp;
    <!-- 具名插槽 -->
    <slot name="aa">爬山吗?</slot>
    <slot name="bb" :config="item">这是?</slot>
  </div>
</template>

父组件:

<template>
  <child>
    <span>qiuer</span>
    <span slot="aa">你吃饭了吗?</span>
    <div slot="bb" slot-scope="scope">
      <span>{{ scope.config.label }}</span>
    </div>
  </child>
</template>

2. vue 2.6.0 之后

vue 2.6.0 起引入了 v-slot

2.1 当只有默认插槽无具名插槽时

子组件 child.vue :

<template>
  <div>
    <h1>hi~</h1>
    <slot v-bind:user="user">
      <div>路见不平一声吼~</div>
    </slot>
    <h1>end~</h1>
  </div>
</template>

父组件:

<template>
  <child v-slot="slotProps">
    {{ slotProps.user.name }}
  </child>
  <!-- 或者 -->
  <child v-slot="{ user }">
    {{ user.name }}
  </child>
  <!-- 或者,将 user 重名为 person -->
  <child v-slot="{ user: person }">
    {{ person.name }}
  </child>
  <!-- 或者,定义后备内容,用于插槽 prop 是 undefined 的情形 -->
  <child v-slot="{ user = { name: '小红' } }">
    {{ user.name }}
  </child>

  <!-- 缩写:使用缩写必须具名 -->
  <child #default="{ user }">
    {{ user.name }}
  </child>

</template>

2.2 具名插槽

当有多个插槽时,需要使用完整的插槽语法。

子组件 child.vue :

<template>
  <div>
    <div>
      <slot name="aa"></slot>
    </div>
    <div>
      <slot>
        <a v-bind:href="url"  class="nav-link">Submit</a>
      </slot>
    </div>
    <div>
      <slot name="bb" v-bind:user="user"></slot>
    </div>
  </div>
</template>

父组件:

<template>
  <child url="/about">
    <template v-slot:aa>
      <h1>这是具名插槽 aa</h1>
    </template>
    <template v-slot:default>
    关于我们
    </template>
    <template v-slot:bb="slotProps">
      <h1>这是具名插槽 bb</h1>
      <div>{{ slotProps.user.name }}</div>
    </template>

    <!-- 根据需求也可以使用动态插槽名 -->
    <!-- <template v-slot:[dynamicSlotName]>
    </template> -->
  </child>

  <!-- 缩写 -->
  <child url="/about">
    <template #aa>
      <h1>这是具名插槽 aa</h1>
    </template>
    <template #default>
    关于我们
    </template>
    <template #bb="{ user }">
      <h1>这是具名插槽 bb</h1>
      <div>{{ user.name }}</div>
    </template>
  </child>

</template>

2.3 默认插槽缩写不能与具名插槽混用

默认插槽缩写不能与具名插槽混用,因为混用会导致作用域不明确。以下是错误示例:

子组件 child.vue :

<template>
  <div>
    <div>
      <slot v-bind:user="user">
        <a v-bind:href="url" class="nav-link">Submit</a>
      </slot>
    </div>
    <div>
      <slot name="bb" v-bind:memu="item"></slot>
    </div>
  </div>
</template>

父组件:

<template>
  <child url="/about" v-slot="slotProps">
    {{ slotProps.user.name }}
    <template v-slot:bb="otherSlotProps">
      slotProps在此不可用
    </template>
  </child>
</template>

3. $slots

$slots:组件插槽集,即组件所有插槽的集合(默认插槽、具名插槽)。例如:通过 this.$slots.default 获取组件的默认插槽。