Component 概念為 React 所發明,讓我們可以將 HTML、CSS 與 JavaScript 封裝成 Component,Vue、Angular 也使用 Component ,至此 3 大 Framework 都採用 Component-based 架構。
Version
macOS Catalina 10.15.6
WebStorm 2020.2
Vue 2.6.11
Introduction
Vue instance 有自己的 data
、methods
、computed
、watch
property,但 Vue instance 只是 HTML 的代言人,讓我們在 JavaScript 控制 HTML,但若要 重複使用
就不是那麼方便,此時我們需要 component。
除此之外,component 也讓我們在開發時實踐 Divide and Conquer
哲學,先將需求切成小小 component,然後各自擊破,最後再將 component 組合起來,如此 component 也更加 單一職責
、更 容易維護
與 重複使用
。
Component
以 component 實現 Hello World。
App.vue
<template>
<hello-world></hello-world>
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
我們發現 App.vue
分兩區,<template/>
負責 HTML,而 <script/>
則負責 JavaScript。
第 1 行
<template>
<hello-world></hello-world>
</template>
由原本的 <span>Hello World</span>
,變成自訂的 hello-world
tag。
自訂的 HTML tag 名稱,無論使用 camelCase,CamelCase,最後 Vue 都會改用 kebab-case (全小寫,單字間以
-
隔開),這是 W3C 所建議,且必須是 2 個單字,避免用一個單字與 HTML 預設 tag 重複
第 6 行
import HelloWorld from '@/components/hello-world.vue'
將 HelloWorld
component 引入,component 會使用 CamelCase。
10 行
components: {
HelloWorld
}
將剛剛 import 進的 HelloWorld
宣告在 components
property 下。
HelloWorld.vue
<template>
<span>Hello World</span>
</template>
<script>
export default {
name: 'HelloWorld',
}
</script>
第 1 行
<template>
<span>Hello World</span>
</template>
將原本的 <span>Hello World</span>
搬到 HelloWorld.vue
的 HTML template 內。
第 5 行
<script>
export default {
name: 'HelloWorld',
}
</script>
在 <script/>
寫 JavaScript。
第 6 行
export default {
ES6 稱為 default export,一個 module 內只能有一個 function 或一個 object 使用 default export,其他都必須使用 named export。
Vue 習慣將 component 使用 default export,由使用端自行對 component 命名
第 7 行
name: 'HelloWorld',
Vue 的 component 名稱習慣使用 CamelCase。
MVVM vs. Component
上下使用了兩個 counter,但本質是同一個 MyCounter
component,但各自維護 state。
App.vue
<template>
<div>
<my-counter></my-counter>
<my-counter></my-counter>
</div>
</template>
<script>
import MyCounter from '@/components/MyCounter.vue'
export default {
name: 'App',
components: {
MyCounter
}
}
</script>
目前 Vue component 的 data 都是直接寫在 HTML template 內,我們知道 MVVM 的精髓就是 data binding,要如何將 MVVM 與 component 兩種架構合而為一呢 ?
第 3 行
<my-counter></my-counter>
使用自訂的 <my-counter></my-counter>
。
第 9 行
import MyCounter from '@/components/MyCounter.vue'
export default {
name: 'App',
components: {
MyCounter
}
}
import 進 MyCounter
,並在 components
property 內宣告了 MyCounter
。
MyCounter.vue
<template>
<div>
<div>{{ counter }}</div>
<button @click="add">+1</button>
</div>
</template>
<script>
let add = function() {
this.counter++
}
export default {
name: 'MyCounter',
data: () => ({
counter: 0
}),
methods: {
add
}
}
</script>
15 行
data: () => ({
counter: 0
}),
data
部分,由原本 Vue instance 的 data
property 改成 data()
function,回傳 object。
這裡有 3 種寫法:
- OOP method
- Function expression
- Arrow function
OOP Method
data() {
return {
counter: 0
}
}
使用 ES6 類似 OOP method 寫法。
Function Expression
data: function() {
return {
counter: 0
}
}
使用 ES5 的 function expression 寫法。
Arrow Function
data: () => ({
counter : 0
})
使用 ES6 的 arrow function。
因為 Object 與 arrow function 的 function body 都使用 {}
,所以 ES6 特別規定當 arrow function 回傳 Object 時,需在 {}
外加上 ()
識別。
個人較喜歡 ES6 的 arrow function,因為簡潔沒有贅字,此部分可依個人品味決定。
18 行
methods: {
add
}
在 methos
property 內宣告 add
method。
第 9 行
let add = function() {
this.counter++
}
定義 add()
實現 counter
累加。
Conclusion
- Vue 提供了 component 與 Vue file,讓我們將 HTML、CSS 與 JavaScript 使用 component 包起來,方便閱讀,也更容易維護
- MVVM 可以與 component 完美結合,但
data
property 必須使用data
function - Vue 並非不能使用 arrow function,只要能分辨何時可用即可