vue slot 定义以及使用

39 阅读2分钟

在 Vue.js 中,<slot> 是一个非常重要的概念,用于实现组件间的动态内容插槽功能。通过 <slot>,父组件可以向子组件传递任意内容,这使得组件更加灵活和可复用。

<slot> 的基本用法:

  1. 默认插槽:

    • 当没有指定 name 属性时,<slot> 表示默认插槽。
    • 父组件可以将任意内容放置在子组件标签内,这些内容将会填充到子组件的 <slot> 位置。
  2. 具名插槽:

    • 通过 name 属性定义具名插槽。
    • 父组件使用 <template v-slot:name> 或 slot="name"(Vue 2)来指定要插入的内容。
  3. 作用域插槽:

    • 允许父组件访问子组件的数据或方法。
    • 通过 v-slot 指令结合变量名来定义作用域插槽。

下面是一些具体的示例来解释这些概念。

示例 1: 默认插槽

子组件 (ChildComponent.vue):

vue
深色版本
1<template>
2  <div>
3    <p>这是一个子组件。</p>
4    <slot></slot>
5  </div>
6</template>

父组件 (ParentComponent.vue):

vue
深色版本
1<template>
2  <div>
3    <child-component>
4      <p>这是从父组件传递过来的内容。</p>
5    </child-component>
6  </div>
7</template>
8
9<script>
10import ChildComponent from './ChildComponent.vue';
11
12export default {
13  components: {
14    ChildComponent,
15  },
16};
17</script>

示例 2: 具名插槽

子组件 (ChildComponent.vue):

vue
深色版本
1<template>
2  <div>
3    <header>
4      <slot name="header"></slot>
5    </header>
6    <main>
7      <slot name="main"></slot>
8    </main>
9    <footer>
10      <slot name="footer"></slot>
11    </footer>
12  </div>
13</template>

父组件 (ParentComponent.vue):

vue
深色版本
1<template>
2  <div>
3    <child-component>
4      <template v-slot:header>
5        <h1>这是头部内容</h1>
6      </template>
7      <template v-slot:main>
8        <p>这是主要内容</p>
9      </template>
10      <template v-slot:footer>
11        <p>这是底部内容</p>
12      </template>
13    </child-component>
14  </div>
15</template>
16
17<script>
18import ChildComponent from './ChildComponent.vue';
19
20export default {
21  components: {
22    ChildComponent,
23  },
24};
25</script>

示例 3: 作用域插槽

子组件 (ChildComponent.vue):

vue
深色版本
1<template>
2  <div>
3    <p>这是子组件的标题:{{ title }}</p>
4    <slot :title="title"></slot>
5  </div>
6</template>
7
8<script>
9export default {
10  data() {
11    return {
12      title: 'Hello World',
13    };
14  },
15};
16</script>

父组件 (ParentComponent.vue):

vue
深色版本
1<template>
2  <div>
3    <child-component>
4      <template v-slot="{ title }">
5        <p>{{ title }} 是从子组件传递过来的。</p>
6      </template>
7    </child-component>
8  </div>
9</template>
10
11<script>
12import ChildComponent from './ChildComponent.vue';
13
14export default {
15  components: {
16    ChildComponent,
17  },
18};
19</script>

注意事项:

  • 在 Vue 2 中,使用 slot="name" 来定义具名插槽。
  • 在 Vue 3 中,推荐使用 v-slot:name 语法来定义具名插槽,更加清晰且易于理解。
  • 作用域插槽允许父组件访问子组件的数据或方法,增强了组件间的数据交互能力。

<!-- 定义: -->
<!-- <slot name="name" $slots.reference/> -->
<template>
  <transfer-panel
    ref="leftPanel"
    :data="sourceData"
    :option-render="optionRender"
    :placeholder="panelFilterPlaceholder"
    :title="leftPanelTitle"
    :filterable="filterable"
    :format="format"
    :filter-method="filterMethod"
    :default-checked="leftDefaultChecked"
    :props="props.props"
    @checked-change="onSourceCheckedChange"
    >
    <slot name="left-footer" />
    <template v-if="$slots.reference">
          <slot name="reference" />
        </template>
    </transfer-panel>
</template>



<!-- 使用: -->
 <!-- #name  v-slot:name slot="name" -->

<template>
  <transfer-panel ref="leftPanel" :data="sourceData" :option-render="optionRender" :placeholder="panelFilterPlaceholder"
    :title="leftPanelTitle" :filterable="filterable" :format="format" :filter-method="filterMethod"
    :default-checked="leftDefaultChecked" :props="props.props" @checked-change="onSourceCheckedChange">
    <template #left-footer>
      <el-button class="transfer-footer" size="small">Operation</el-button>
    </template>
    <template #right-footer>
      <el-button class="transfer-footer" size="small">Operation</el-button>
    </template>  
    或者
    <template #reference>
      <el-button @click="visible = true">Delete</el-button>
    </template>
    或者
    <el-button slot="reference" @click="visible = true">vue2的写法</el-button>
    或者
    <el-button v-slot:reference @click="visible = true">vue3的写法</el-button>

  </transfer-panel>
</template>


<!-- 作品域插槽定义: -->
<template>
  <div>
    <p>这是子组件的标题:{{ title }}</p>
    <slot :title="title"></slot>
  </div>
  </template>
<!-- 作品域插槽使用: -->
<child-component>
  <template v-slot="{ title }">
    <p>{{ title }} 是从子组件传递过来的。</p>
  </template>
</child-component>