請啟用 Javascript 查看內容

Vue元件 - Slot 插槽

 ·  ☕ 3 分鐘

竹白的 Vue 記事本 目錄

Slot 插槽

元件就是用來重複使用的,但不可能每次使用都用同樣的模板。而 <slot> 插槽 可以使我們的元件更佳彈性,能從外層將模板放置指定位置上。

匿名插槽

首先,這是沒有 <slot> 的元件:

1
2
3
4
5
6
7
Vue.component('c-demo', {
  template: `
    <div>
      <p>Demo</p>
    </div>
  `,
});

因此如果我們直接在元件 tag 放置內容是沒有意義的。

1
2
3
4
<c-demo><p>123</p></c-demo>

<!-- 渲染 -->
<div><p>Demo</p></div>

想要新增的內容並不會被渲染出來。

這裡要使用插槽,需要在元件模板加上 <slot>

1
2
3
4
5
6
7
8
Vue.component('c-demo', {
  template: `
    <div>
      <p>Demo</p>
      <slot></slot>
    </div>
  `,
});
1
2
3
4
5
6
7
<c-demo><p>123</p></c-demo>

<!-- 渲染 -->
<div>
  <p>Demo</p>
  <p>123</p>
</div>

原本 <slot> 的位置就會被替換成添加的元素。

CodePen Demo:Vue 2.x - 匿名插槽

如果你設置多個 <slot>,內容就會重複:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Vue.component('c-demo', {
  template: `
    <div>
      <p>Demo</p>
      <slot></slot>
      <slot></slot>
      <slot></slot>
    </div>
  `,
});
1
2
3
4
5
6
7
8
9
<c-demo><p>123</p></c-demo>

<!-- 渲染 -->
<div>
  <p>Demo</p>
  <p>123</p>
  <p>123</p>
  <p>123</p>
</div>

另外,<slot> 內可以加上預設元素:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Vue.component('c-demo', {
  template: `
    <div>
      <p>Demo</p>
      <slot>
        <p>預設內容</p>
      </slot>
    </div>
  `,
});

如果沒有添加元素,就會顯示預設元素。

具名插槽

slot 特性語法在 2.6.0 起被廢棄,由 v-slot 指令取代,有興趣可以參考 官方文件

1. 基本範例

如果我們有多個插槽的需求,就需要為每個 <slot> 加上 name 特性,也就是具名插槽:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Vue.component('c-demo', {
  template: `
    <div>
      <h1>
        <slot name="title"></slot>
      </h1>
      <main>
        <slot name="content"></slot>
      </main>
      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>
  `,
});

在外層插入元素時,必須在 <template> 元素上使用 v-slot 指令,指定元素插入的位置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<c-demo>
  <template v-slot:title>
    Title
  </template>
  <template v-slot:content>
    <p>123456</p>
  </template>
  <template v-slot:footer>
    end
  </template>
</c-demo>

<!-- 渲染 -->
<div>
  <h1>Title</h1>
  <main>
    <p>123456</p>
  </main>
  <footer>end</footer>
</div>

CodePen Demo:Vue 2.x - 具名插槽

2. 混用

如果使用具名插槽又使用匿名插槽:

1
2
3
4
5
6
7
8
Vue.component('c-demo', {
  template: `
    <div>
      <slot></slot>
      <slot name="content"></slot>
    </div>
  `,
});
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<c-demo>
  <p>111</p>
  <template v-slot:content>
    <p>222</p>
  </template>
  <p>333</p>
  <template>
    <p>444</p>
  </template>
  <p>555</p>
</c-demo>

<!-- 渲染 -->
<div>
  <p>111</p>
  <p>333</p>
  <p>444</p>
  <p>555</p>
  <p>222</p>
</div>

任何沒有被包裹在帶有 v-slot<template> 的內容都會被放進匿名插槽中。

CodePen Demo:Vue 2.x - Slot 插槽測試

匿名插槽預設 name 特性名稱為 default,因此如果我們使用 <template v-slot:default> 時,這裡的內容將被放置在匿名插槽中,而且任何沒有被包裹在帶有 v-slot<template> 的內容都將無效:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<c-demo>
  <p>1111</p>
  <template v-slot:default>
    <p>222</p>
  </template>
  <template>
    <p>333</p>
  </template>
</c-demo>

<!-- 渲染 -->
<p>222</p>

CodePen Demo:Vue 2.x - Slot 插槽測試2

3. 縮寫

另外 v-slot 指令也有縮寫 #

1
2
3
4
<template v-slot:#title></template>

<!-- 等同 -->
<template #title></template>

與其他縮寫一樣,只有在有參數時,才能使用。

作用域插槽

元件 tag 位於父層,如果希望插槽訪問元件的資料,你可以這樣做。

在設置插槽時,可以綁定 插槽 prop

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Vue.component('c-demo', {
  template: `
    <div>
      <slot :obj="abc"></slot>
    </div>
  `,
  data() {
    return {
      abc: {
        a: 'aaa',
        b: 'bbb',
      },
    };
  },
});

obj 為我們定義的 插槽 propabc 為綁定的資料。

接下來,我們就能在父層使用 v-slot 指令,可以取得一個物件(可以任意命名),這個物件會包含 <solt> 上所有綁定的 插槽 prop

1
2
3
4
5
<c-demo >
  <template v-slot="myData">
    {{ myData.obj.a }}
  </template>
</c-demo>

CodePen Demo:Vue 2.x - 作用域插槽

但要注意,上面 v-slot="myData" 屬於匿名插槽的縮寫,當你有使用其它具名插槽時,不能與匿名插槽的縮寫混用,會導致作用域不明確,應該要正確使用原本應該要有的語法 v-slot:default="myData"

另外,我們還可以解構插槽,例如將上面程式碼改成這樣:

1
2
3
4
5
<c-demo >
  <template v-slot="{ obj }">
    {{ obj.a }}
  </template>
</c-demo>

甚至可以定義預設值:

1
2
3
4
5
<c-demo >
  <template v-slot="{ obj = { a: 'a'} }">
    {{ obj.a }}
  </template>
</c-demo>

竹白
作者
竹白
前端筆記

文章目錄