Skip to content

插槽内容与出口

组件能够以 props 为载体传递 JS 值,同样,组件也可以传递模板(template)内容。

html
<FancyButton>
  Click me! <!-- 插槽内容 -->
</FancyButton>

<button class="fancy-btn">
  <slot></slot> <!-- 插槽出口 -->
</button>

父元素传递的模板将在出口处被渲染。

作用域

由于插槽内容定义在父组件上,因此可以直接访问到父组件的作用域,当然它不能访问子作用域。

默认内容

在插槽出口处的内容即为插槽的默认渲染内容:

html
<button type="submit">
  <slot>
    Submit <!-- 默认内容 -->
  </slot>
</button>

slot 插槽

  • 分类:默认插槽,具名插槽,作用域插槽;
  • 在一个 category 组件中渲染多种不同类型的组件(简化 v-if 条件渲染),增强了组件的灵活性和可(重)复用性。

默认插槽

父组件

html
<template>
  <div class="father">
    <h3>父组件</h3>
    <div class="content">
      <Category title="热门游戏列表">
	    <h2>热门游戏列表</h2>
	    <!--可以不用props传标题-->
        <ul>
          <li v-for="g in games" :key="g.id">{{ g.name }}</li> 
          <!--双标签中的内容会被插入到子组件的slot标签中-->
        </ul>
      </Category>
      <Category title="今日美食城市">
        <img :src="imgUrl" alt="">
      </Category>
      <Category title="今日影视推荐">
        <video :src="videoUrl" controls></video>
      </Category>
    </div>
  </div>
</template>

子组件

html
<template>
  <div class="category">
    <h2>{{title}}</h2>
    <slot>默认内容</slot>
    <!--如果插槽中没有内容则呈现默认内容-->
  </div>
</template>

具名插槽

  • 默认插槽其实也有默认属性,值为 defalut

具名插槽就是在父组件中可以声明插槽的名称以根据插槽的名称来传递内容。 父组件 插槽中可嵌套 template 标签。

html
<template>
  <div class="father">
    <h3>父组件</h3>
    <div class="content">
      <Category>
        <template v-slot:s2>
          <ul>
            <li v-for="g in games" :key="g.id">{{ g.name }}</li>
          </ul>
        </template>
        <template #: s1>
        <!--简写形式-->
          <h2>热门游戏列表</h2>
        </template>
      </Category>
    </div>
  </div>
</template>

子组件

html
<template>
  <div class="category">
    <slot name="s1">默认内容1</slot>
    <slot name="s2">默认内容2</slot>
  </div>
</template>
动态插槽名

[] 包括变量即可。

html
<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>

  <!-- 缩写为 -->
  <template #[dynamicSlotName]>
    ...
  </template>
</base-layout>

条件插槽

通过判断具名插槽的 name 指定的插槽是否存在来决定渲染某些内容。 $slots 是一个对象,包含了所有定义的插槽。

html
<template>
  <div class="card">
    <div v-if="$slots.header" class="card-header">
      <slot name="header" />
    </div>
</template>

作用域插槽 (范围插槽)

因为插槽摸不到子组件的数据,所以需要一种方式让插槽在渲染时获得一部分子组件提供的数据。 ![[scoped-slots.B67tIPc5.svg]] 本质上是子组件向父组件的 props 传递,传递的结果可以在父组件上通过 v-slot 获取。 也可以直接解构 v-slot

html
<MyComponent v-slot="{ text, count }">
  {{ text }} {{ count }}
</MyComponent>

具名作用域插槽 props

可以通过 #name="xxxProps" 的形式拿到子组件传递的 props:

html
<MyComponent>
  <template #header="headerProps">
    {{ headerProps }}
  </template>
</MyComponent>

<slot name="header" message="hello"></slot>

name 是保留的 props,不会被传递给父组件。 具名插槽和默认插槽一同使用的时候,默认插槽也许要显式被 template 包裹。 使用场景

html
<ul>
  <li v-for="item in items">
    <slot name="item" v-bind="item"></slot>
  </li>
</ul>

动态地将参数传递给父组件上定义的插槽 template 完成渲染。 无渲染组件 一些组件可能只包括了逻辑而不需要自己渲染内容,视图输出通过作用域插槽全权交给了消费者组件。我们将这种类型的组件称为无渲染组件。 渲染鼠标指针位置: Vue SFC Playground (vuejs.org),将渲染逻辑全部交给父组件,子组件只负责逻辑部分。