文章

組件的插槽 (Slots)

在 Vue 3 中,插槽 (Slots) 是用來讓父組件向子組件傳遞內容的一種方式。透過插槽,父組件可以將自定義的 HTML 內容插入到子組件的指定位置,從而使得子組件能夠更靈活地展示和渲染內容。插槽為組件提供了一種擴展性,使得組件在不同的場景中能夠重複利用。

1. 什麼是插槽?

插槽是 Vue 中的一種內容分發方式。父組件可以通過插槽向子組件插入 HTML 結構或其他模板內容,子組件預留特定的位置來顯示這些內容。插槽可以像占位符一樣,允許父組件根據需求向子組件提供動態內容。


2. 基本插槽 (Default Slots)

最基本的插槽是 默認插槽。這意味著父組件可以將內容插入子組件中,而子組件可以通過 <slot> 元素來顯示該內容。

範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div id="app">
  <!-- 父組件 -->
  <child-component>
    <p>This is the content from the parent.</p>
  </child-component>
</div>

<script>
const app = Vue.createApp({
  components: {
    'child-component': {
      template: `
        <div>
          <h2>This is the child component</h2>
          <slot></slot> <!-- 插槽,用來展示父組件傳入的內容 -->
        </div>
      `
    }
  }
});

app.mount('#app');
</script>

在這個範例中:

  • 父組件:傳遞了一段 HTML (<p>...</p>) 給子組件。
  • 子組件:使用 <slot></slot> 元素來接收和顯示父組件傳遞的內容。

結果是:

1
2
This is the child component
This is the content from the parent.

這個插槽在子組件的 <slot> 標籤位置插入了父組件提供的內容。


3. 具名插槽 (Named Slots)

有時候,我們希望在子組件中插入多個不同位置的內容,這時可以使用 具名插槽。具名插槽允許父組件針對不同的插槽提供不同的內容,這樣可以靈活控制不同位置的顯示。

具名插槽的使用步驟

  1. 在子組件中定義具名插槽,使用 <slot name="slotName"></slot>
  2. 在父組件中傳入對應的插槽內容,使用 <template v-slot:slotName>v-slot 簡寫。

範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<div id="app">
  <!-- 父組件 -->
  <child-component>
    <template v-slot:header>
      <h1>This is the header</h1>
    </template>

    <template v-slot:footer>
      <p>This is the footer</p>
    </template>
  </child-component>
</div>

<script>
const app = Vue.createApp({
  components: {
    'child-component': {
      template: `
        <div>
          <slot name="header"></slot> <!-- 具名插槽:header -->
          <p>This is the main content of the child component.</p>
          <slot name="footer"></slot> <!-- 具名插槽:footer -->
        </div>
      `
    }
  }
});

app.mount('#app');
</script>

在這個範例中:

  • 父組件向子組件的 headerfooter 具名插槽插入了不同的內容。
  • 子組件定義了兩個具名插槽,並根據傳遞進來的內容來渲染。

結果是:

1
2
3
This is the header
This is the main content of the child component.
This is the footer

4. 作用域插槽 (Scoped Slots)

作用域插槽 是一種進階的插槽功能,允許子組件將數據傳遞回父組件,這樣父組件可以根據這些數據來動態渲染內容。通過作用域插槽,父組件不僅可以插入內容,還可以根據子組件提供的數據來控制內容的顯示。

如何使用作用域插槽

  1. 在子組件中,通過 <slot> 元素傳遞一些數據給父組件。
  2. 父組件可以使用 v-slot 來接收這些數據,並根據數據動態渲染。

範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<div id="app">
  <!-- 父組件 -->
  <child-component v-slot="slotProps">
    <p></p>
  </child-component>
</div>

<script>
const app = Vue.createApp({
  components: {
    'child-component': {
      template: `
        <div>
          <slot :text="message"></slot> <!-- 子組件將 message 傳遞給插槽 -->
        </div>
      `,
      data() {
        return {
          message: 'Hello from child component!'
        };
      }
    }
  }
});

app.mount('#app');
</script>

在這個範例中:

  • 子組件:使用 <slot :text="message"></slot>message 這個數據傳遞給插槽。
  • 父組件:使用 v-slot="slotProps" 接收插槽內傳遞的數據,並顯示出來。

結果是:

1
Hello from child component!

這樣父組件可以根據子組件的數據動態改變插槽內的內容。


5. 默認內容

插槽也可以有默認內容,當父組件沒有提供插槽內容時,子組件會顯示默認的內容。如果父組件提供了內容,則默認內容會被覆蓋。

範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div id="app">
  <!-- 父組件不提供內容時顯示默認內容 -->
  <child-component></child-component>
</div>

<script>
const app = Vue.createApp({
  components: {
    'child-component': {
      template: `
        <div>
          <slot>This is the default content if nothing is provided.</slot>
        </div>
      `
    }
  }
});

app.mount('#app');
</script>

結果是:

1
This is the default content if nothing is provided.

如果父組件不傳遞任何內容,子組件會顯示插槽內的默認文字。如果父組件傳入內容,則會覆蓋默認內容。


6. 具名作用域插槽 (Scoped Named Slots)

具名插槽和作用域插槽可以結合在一起使用,這樣可以在不同的具名插槽中傳遞不同的數據,讓父組件能夠根據子組件提供的數據動態渲染不同區域的內容。

範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<div id="app">
  <child-component>
    <template v-slot:header="slotProps">
      <h1></h1>
    </template>

    <template v-slot:footer="slotProps">
      <p></p>
    </template>
  </child-component>
</div>

<script>
const app = Vue.createApp({
  components: {
    'child-component': {
      template: `
        <div>
          <slot name="header" :title="headerTitle"></slot>
          <p>Main content here.</p>
          <slot name="footer" :info="footerInfo"></slot>
        </div>
      `,
      data() {
        return {
          headerTitle: 'Welcome to the header!',
          footerInfo: 'This is the footer information.'
        };
      }
    }
  }
});

app.mount('#app');
</script>

在這個範例中:

  • 子組件有具名插槽 headerfooter,並且向每個插槽傳遞了不同的數據(headerTitlefooterInfo)。
  • 父組件根據子組件提供的數據來渲染具名插槽內的內容。

結果是:

1
2
3
Welcome to the header!
Main content here.
This is the footer information.

7. 多插槽 (Multiple Slots)

Vue 3 中,子組件可以有多個插槽,這讓組件的內容更加靈活。每個插槽可以根據具名來插入不同的內容,並且支持動態數據傳遞。


總結

  • 插槽 (Slots) 是用來在 Vue 組件中分發和顯示內容的機制,允

許父組件向子組件插入自定義內容。

  • 默認插槽 用於插入不具名的內容,具名插槽 則允許插入特定區域的內容。
  • 作用域插槽 提供了更強大的功能,允許子組件向父組件傳遞數據,從而讓父組件根據數據動態渲染內容。
  • 具名作用域插槽 結合了具名插槽與作用域插槽,讓多插槽模式更加靈活。

插槽使得組件的可重用性和靈活性更高,適用於各種動態模板設計場景。

本文章以 CC BY 4.0 授權