Vue.js (10) - 單一元件檔(Single-file components)

Vue.js

不論是在 Vue 實體中建立區域元件,或是使用 Vue.component 來建立全域元件,這些都只適合在用在簡單的小元件上,當元件變得複雜時,在開發上會變得很沒效率,這時可以使用 Vue 提供的單一元件檔來解決這個問題。

為什麼要使用單一元件檔

我們來看看在使用 Vue 實體或 Vue.component 建立元件時會有什麼缺點。

1. 全域定義的問題

使用 Vue.component 定義的元件是全域的,意謂著元件的名稱不能重複。

2. 字串模板的問題

在元件中的 template 屬性只能使用字串,因此當你在編寫樣板內容時,編輯器就無法以顏色顯示;而且只能以 \ 倒斜線的方式分行,寫起來不方便、效率太差。

3. CSS 的問題

在元件中只能提供 HTML 及 JavaScript ,漏掉了 CSS 的支援。

4. 前置處理的問題

元件預設只能使用 HTML 及 ES5 JavaScript,不能使用前置處理工具,所以像是 Jade 及 Babel 等就無法使用。

單一元件檔可以解決以上的問題,它同時包含了 HTML、JavaScript 及 CSS,而且因為一個檔案就代表一個元件,在管理上也更有效率。同時也支援 Webpack 或 Browserify 等打包工具。

如何使用單一元件檔

單一元件檔的副檔名為 .vue,範例如下:
Vue<template>
  <div class="hello">Hello {{ name }}</div>
</template>

<script>
module.exports = {
  data: function () {
    return {
      name: 'Tony'
    }
  }
}
</script>

<style>
.hello {
  font-size: 3em;
  text-align: center;
  color: green;
}
</style>
不過這個檔案不能直接使用,必須透過 vue-loader 來解析文件,組成一個 CommonJS 模組,最後透過 module.exports 輸出一個 Vue.js 元件。

<template> 區塊

樣板預設使用 HTML,但是可以使用 lang 屬性來指定使用其他的樣板系統,例如:
<template lang="jade">
樣板裡的內容會被編譯成元件的 template 屬性的值。樣板內只能有一個根元素。

這個區塊只能有一個。

<script> 區塊

預設使用 JavaScript。如果有安裝 babel-loader 或 buble-loader 則可以使用 ES2015 語法。要使用其他 JavaScript 套件可以使用 require(),在支援 ES2015 的情況下,也可以用 import 及 export 語法。

這個區塊只能有一個,而且最終必須匯出 Vue.js 物件。

<style> 區塊

預設使用 CSS,也可以換成 SASS,例如:
<style lang="sass">...</style>
<style> 的內容預設是全域的,如果你想讓它只在這個元件中有效(區域),可以加上 scoped 屬性,例如:
<style scoped>...</style>
一個 .vue 文件中可以同時使用全域和區域的 <style> 區塊。

這個區塊可以有零個或多個。

自定義區塊

使用 vue-loader 10.2.0+ 以上版本,你也可以加入自己定義的區塊。

註解

最頂層的註解使用 HTML 註解語法:<!-- 這是註解 -->
區塊中則使用該區塊原本的註解語法。

編輯器外掛

Sublime Text 可以搜尋 vue syntax highlight 外掛,安裝後可以對 .vue 文件做語法色彩顯示。

使用 Vue-cli 工具

Webpack 是一個打包工具,可以將你以模組方式寫的程式碼等等檔案整合成單一個檔案。它非常靈活好用,但是也因為這樣,前置的設定就有點麻煩。

Vue.js 官方提供了一個命令列工具 vue-cli ,其中就提供 Webpack 的配置設定,我們可以直接使用它來建置網站。

安裝及執行

首先使用 npm 或 yarn 來安裝,記得安裝成全域的方便使用:
npm install --global vue-cli
或
yarn global add vue-cli
註:如果使用 yarn ,記得把 yarn global bin 指令顯示的路徑加入 $PATH,不然會出現找不到指令的錯誤。

測試看看指令能不能用,在 shell 中執行:
vue --version
如果輸出版本號就表示指令可以使用。接著就可以來建立專案了。

先切換到你想建立專案的目錄,然後執行:
vue init webpack hello
init 會建立新專案;webpack 是選擇要建立的專案樣板;hello 是專案目錄的名稱。

你可以在 vuejs-templates 查看專案樣板:
  • webpack-simple:只包含 vue-loader 的簡單樣板。
  • webpack:在 webpack-simple 上再包含熱重載、測試、linting、CSS抽取等工具,是最完整的樣板。
  • browserify-simple:只包含 vueify 的簡單樣板。
  • browserify:在 browserify-simple 上再包含熱重載、測試、linting、CSS抽取等工具,是最完整的樣板。
  • simple:只包含一個 html 檔。
註:webpack 和 browserify 都是打包工具,用途一樣擇一使用即可。

安裝指令會透過問問題的方式讓你選擇是否安裝它提供的套件,你可以一路按 Enter 使用預設值。完成後,它會提示你如何開始:
  1. 進入專案目錄:cd hello
  2. 安裝套件:npm installyarn
  3. 執行:npm run devyarn run dev
如果一切順利,會啟動一個開發用的伺服器,並且自動開啟瀏覽器顯示執行的頁面。按 Ctrl + C可以停止伺服器。

你可以查看 README.md,裡面有提到建置相關的指令,例如:
  • npm install:安裝相依套件。
  • npm run dev:運行開發用伺服器,並且在檔案變動時自動重新整理。
  • npm run build:建立最終可執行的檔案,輸出到 dist 目錄。
  • npm run unit:執行單元測試。

撰寫第一個 .vue 文件

index.html

首先來看看專案根目錄下的 index.html:
HTML<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>hello</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>
註解告訴我們,建置的檔案會自動加入,所以這個檔案只提供了最基本的 HTML 內容,沒有 CSS、也沒有 JavaScript 等等內容,唯一要注意的就是 <div id="app"></div> 這是要讓 Vue 執行的進入點。

接著來看 src 目錄,你的主要程式都會放在這。

src/main.js

這個檔案是程式的進入點,是由 build/webpack.base.conf.js 設定檔中的 entry 所指定,如果有需要可以更改它。

為了瞭解整個開發流程,我們先忽略 vue-cli 建立的內容,你可以將 main.js 中的內容全部刪掉或註解,然後輸入以下內容:
JavaScriptimport Vue from 'vue'

/* eslint-disable no-new */
new Vue({
  el: '#app',
  template: '<h1>Hello Vue</h1>'
})
然後執行 yarn run dev,順利的話,你可以在瀏覽器看到結果。

但你很可能會遇到一些錯誤,例如:
Errors:
  2  http://eslint.org/docs/rules/indent
  2  http://eslint.org/docs/rules/no-tabs
  1  http://eslint.org/docs/rules/eol-last
  1  http://eslint.org/docs/rules/no-new
ESLint 是一個 JavaScript 語法檢查器,我們在建立專案時,選擇的是 JavaScript Standard Style ,所以 ESLint 用這個標準來幫我們檢查語法風格,這些錯誤訊息只是說風格不符,並不是真的程式有錯。

要如何修改:
  • indent:縮排的方式。標準必須用 2 個空白,如果你用 tab 就會出現這個錯誤。
  • no-tabs:是否允許 tab 。標準不能使用 tab ,如果你用了就出現錯誤。
  • eol-last:檔案結尾是否要保留一個空行。標準要求要,檔案最後沒保留空白行就會出現錯誤。
  • no-new:是否允許使用 new。標準不允許,用了就會出現錯誤。但是因為我們必須使用,所以加一行註解來取消 ESLint 的檢查。
如果你想用 tab 來縮排的話,可以修改 ESLint 的檢查規則,用編輯器打開專案根目錄下的 .eslintrc.js ,你可看到它的規則是繼承(extends)自 standard,後面的 rules項目可以讓你設定規則,這裡設定的規則會覆蓋繼承的規則。

我們可以加入 2 行來強制使用 tab:
'rules': {
    'indent': ['error', 'tab'],
    'no-tabs': 0,
    ...略
想要查詢更多的規則,可以看 ESLint Rules

回到 main.js 上,你應該會發現,程式碼和一開始學 Vue.js 時差不多,只是拆成 index.htmlmain.js 兩個檔案。

src/MyApp.vue

來建立我們的第一個 .vue 檔,MyApp.vue 內容如下:
Vue<template>
  <div>
    <h1>Hello</h1>
    <p class="hello">{{ msg }}</p>
  </div>
</template>

<script>
export default {
  data () {
    return {
      msg: '這是第一個 Vue 元件檔!'
    }
  }
}
</script>

<style scoped>
h1 {
  color: green;
}

.hello {
  font-size: 1.5em;
  color: blue;
}
</style>
<template> 區塊只能(必須)有一個根元素,其他元素只能放在其中。

<script> 必須要匯出 Vue.js 物件。

我們的 .vue 檔完成了,怎麼用呢?回到 main.js 加入內容後如下:
JavaScriptimport Vue from 'vue'
import MyApp from './MyApp'

/* eslint-disable no-new */
new Vue({
  el: '#app',
  template: '<MyApp></MyApp>',
  components: { MyApp }
})
這裡記得 from 的部份,如果使用的是 node_modules 也就是由 npm / yarn 安裝的套件,直接寫套件的名稱;而如果是自己的 JavaScript 檔,則要在檔名前加上 ./

接著我們指定 components 為 MyApp.vue 所匯出的元件。如果有多個元件,可以逗號分隔。

然後就能把樣板內容換成 <MyApp></MyApp>,也可以寫成 <MyApp/>,立即使用我們所建立的元件。

以下示範如何把其他 .vue 檔加在一起,這裡借用原本的 App.vue
方式一:加在 main.js
JavaScriptimport Vue from 'vue'
import MyApp from './MyApp'
import App from './App'

/* eslint-disable no-new */
new Vue({
  el: '#app',
  template: '<div><MyApp/><App/></div>',
  components: { MyApp, App }
})
記住,template 只能有一個根元素,所以我們要用 <div> 來包含它們。這樣你應該知道如何加入其他元件了。現在,將 main.js 還原,以接續下一個方式。

方式二:加在 MyApp.vue 中:
HTML<template>
  <div>
    <h1>Hello</h1>
    <p class="hello">{{ msg }}</p>
    <App/><!-- 元件放在這 -->
  </div>
</template>

<script>
import App from './App'

export default {
  data () {
    return {
      msg: '這是第一個 Vue 元件檔!'
    }
  },
  components: { App }
}
</script>

...略
<script> 中一樣 import 元件檔進來,接著指定給 components,然後就能在 <template> 中使用它了。

現在你已經知道怎麼寫 .vue 檔、怎麼使用 .vue 檔及怎麼混合使用多個 .vue 檔了。你可以試試看把 components/Hello.vue 加進來:
HTML<template>
  <div>
    <h1>Hello</h1>
    <p class="hello">{{ msg }}</p>
    <App/>
    <Hello/>
  </div>
</template>

<script>
import App from './App'
import Hello from './components/Hello'

export default {
  data () {
    return {
      msg: '這是第一個 Vue 元件檔!'
    }
  },
  components: { App, Hello }
}
</script>

...略

Build

最後,當你完成了所有的工作,就可以執行
npm run build
或
yarn run build
所有的內容就會組合打包起來輸出到 dist 目錄中。

dist 中的內容必須放在伺服器中才能執行,所以在開發中可以使用
npm run dev
或
yarn run dev
在開發伺服器中瀏覽。

元件的命名及使用

不管你的元件如何命名,在使用的時候都要注意大小寫可能造成的名稱問題。在 HTML 中,任何元素都是不分大小寫的,所以元件名稱在轉成 HTML 元素時會轉成小寫並加上分隔線,以下舉例:
  • 檔案名稱 App.vue:轉換成 <app></app>,即使用你寫成 <App></App> 是可以,但瀏覽器看到的是仍是小寫的元素。
  • 檔案名稱 MyApp.vue:轉換成 <my-app></my-app>,這就是要注意的情況,如果元素名稱用錯,Vue.js 會出現未註冊元件的警告。
本文網址:http://blog.tonycube.com/2017/05/vuejs-10-single-file-components.html
Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀

我要留言

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。