Contents

Vue Component 沒有 Render 出來

在 Vue 開發中,使用自訂元件前必須先「註冊」該元件,否則 Vue 不知道這個標籤對應到哪個元件,就不會渲染出來。這是新手常見的問題之一。

問題描述

在 Options API 中,如果直接在 template 使用元件而沒有在 components 選項中宣告,該元件就不會出現,也不會有明顯的錯誤(只是靜默地不渲染),Vue DevTools 或 Console 可能會顯示類似以下的警告:

1
2
[Vue warn]: Failed to resolve component: MyComponent
If this is a native custom element, make sure to exclude it from component resolution...

Vue 2:Options API 的元件註冊

局部註冊(推薦)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import Header from './components/Header.vue'
import MyAnimeList from './components/MyAnimeList.vue'

export default {
  components: {
    Header,
    MyAnimeList
  },
  // ...
}

components 中宣告後,就可以在 template 中使用:

1
2
3
4
5
6
<template>
  <div>
    <Header />
    <MyAnimeList />
  </div>
</template>

全局註冊

全局註冊後,所有元件都不需要重複宣告:

1
2
3
4
5
// main.js
import Vue from 'vue'
import Header from './components/Header.vue'

Vue.component('Header', Header)  // 全局註冊

全局註冊的缺點是:即使某個頁面用不到,這個元件仍然會被打包進去,增加 bundle 大小。

Vue 3:Composition API 與 <script setup>

Options API(同 Vue 2 寫法)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import { defineComponent } from 'vue'
import Header from './components/Header.vue'

export default defineComponent({
  components: {
    Header
  },
  setup() {
    // ...
  }
})

<script setup>(最推薦的寫法)

使用 <script setup> 時,import 進來的元件會自動註冊,不需要手動在 components 中宣告,這也是為什麼有些人用 setup 寫法反而沒問題的原因:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<script setup>
import Header from './components/Header.vue'
import MyAnimeList from './components/MyAnimeList.vue'
// import 就等於自動註冊,可直接在 template 使用
</script>

<template>
  <Header />
  <MyAnimeList />
</template>

全局註冊(Vue 3)

1
2
3
4
5
6
7
8
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import Header from './components/Header.vue'

const app = createApp(App)
app.component('Header', Header)  // 全局註冊
app.mount('#app')

局部 vs 全局註冊的選擇

局部註冊 全局註冊
Tree-shaking ✅ 支援(未使用不打包) ❌ 不支援
使用便利性 每個元件都要 import 一次設定到處使用
適合場景 一般頁面元件 全站共用的基礎元件(Button、Icon 等)

參考資料