前情提要
前面兩篇講了vue相關的語法,是不是覺得少了點什麼,這篇是重頭戲,介紹Vue Instance宣告時有哪些options可設定,有什麼樣的相關技巧以及Component的應用,筆者就以自身開發角度分享實戰經驗。
使用工具及環境參考[Vue]Vue基本語法。
內容
Vue Instance
建立實體
使用new
關鍵字建立vue實體
1 | var vm = new Vue({ |
相關屬性介紹
el
最重要且一定要設定的option,vue的作用域,與jquery selector
類似方式宣告
1 | // 表示vue作用域為id=app之div區塊 |
data
vue中使用到的參數,皆宣告於此
1 | new Vue({ |
methods
vue宣告之使用到的function,皆宣告於此
1 | new Vue({ |
Lifecycle Hook
vue在實體化過程中開放hook讓我們監聽,看官網圖比較順
以上以筆者經驗來說,最常使用的是created
、mounted
、beforeDestroy
這三個事件,使用時機為
created
:會Initial頁面上的資料來源,如下拉式選單sourcemounted
:監聽事件宣告,或者確保vue實體化完才可以做的事情;若分不清楚,在此宣告是最安全的beforeDestroy
:若頁面上有監聽事件則,需於此事件中解除監聽off
computed
若頁面上使用變數為經過運算後才得到值,可以使用computed
option中宣告它,在vue中使用時與data
參數無差別,差別在於若運算邏輯中有參考到別的參數則,該參數有變化則會重新運算
1 | new Vue({ |
官網中提到假設computed
變數中無參考到其他參數,而是一般function執行,例
1 | computed: { |
則比較適合使用methods
方式來宣告,才會頁面rerender時會再重新呼叫一次function
watch
監聽參數變化,vue預設會提供新舊值讓我們操作
1 | watch: { |
methods/computed/watch這三個option一定要慎選使用,多思考一秒會讓你事半功倍,不留下臭蟲
mixin
mixin
看官網解釋重點就是mixed
這個字,表是我們可以定義一個component
,有完整的vue實體化options可以設定,並使用mixins
option使用我們剛定義好的component。以筆者親身經驗來說,若有共用function的需求,我會定一個mixin
用component,裡頭會使用methods
宣告共用function。最後,任一個component中使用mixins
option宣告並使用共用function。
1 | // 定義完整的Component當作MyMixin |
1 | // 示範使用上述宣告之MyMixin |
執行後的結果
Component介紹
基本上,若使用webpack full
template產生之專案則,每一個.vue
檔案都是一個獨立的component,vue instance裡可設定的所有options(除el)皆可設定。
使用技巧
筆者習慣上,依功能區分component,以利達到Component最小化,例如Layout中會抽Navigation、Sidebar、Footer等;若查詢頁面中則會抽Conditions、Pagination等Component。
傳遞資料
以上述情形,會遇到Component間傳遞資料的需求,假設以查詢頁面為例,符合統一頁面設計規則,每個查詢頁面中會放置「新增」按鈕,這種統一需求會一併抽至conditions
component,等於每個功能的「新增」url設定需傳至conditions
component中。傳遞資料會分為兩種情況,若將import
方式引入component則,引入進來的component稱為child component,本身component則稱為parent component,因此會分為父傳子
及子傳父
的傳遞方式。筆者針對這個傳遞資料的示範會使用兩個component完成:conditions
及componentdemo
。
父傳子
父傳子的方式簡單多了,在child component
中使用props
option設定參數的宣告,parent component
中透過v-on
的方式指定該參數的值即可。
- Child Component
Conditions.vue
1 | <template> |
- Parent Component
ComponentDemo.vue
1 | <template> |
子傳父
以上述例子,跟著筆者繼續完成子傳父的功能吧,假設查詢
按鈕按下去後將查詢條件區塊中使用者所填選的值傳送至父component中做查詢動作,我們需要使用$emit
的方式通知。
- Child Component
Conditions.vue
- 宣告data參數值:conditions
- 將conditions參數透過
v-model
bind至查詢條件區塊中 查詢
鈕中加入click事件,使用v-on:click
,function名稱為searchProcess
searchProcess
function中emit
事件,事件名稱為searchEmit
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68<template>
<div id="conditions">
<div class="card">
<div class="card-header">
<!-- 外部連結 -->
<a :href="insertUrl"
class="btn btn-secondary"
target="_blank">
<i class="fa fa-plus"></i> 新增
</a>
<!-- 內部vue router path -->
<!-- <router-link :to="{ path: insertUrl }">
<i class="fa fa-plus"></i> 新增
</router-link> -->
</div>
<div class="card-body">
<form class="form form-horizontal">
<div class="row">
<div class="col-4 form-group">
<label>查詢條件一</label>
<input type="text"
class="form-control"
v-model="conditions.query1">
</div>
<div class="form-group col-4">
<label>查詢條件二</label>
<select class="form-control"
v-model="conditions.query2">
<option value=""></option>
<option value="1">下拉選單一</option>
<option value="2">下拉選單二</option>
</select>
</div>
</div>
<div class="row">
<div class="col">
<button class="btn btn-danger">
<i class="fa fa-times"></i> 取消
</button>
<button class="btn btn-primary"
@click.prevent="searchProcess()">
<i class="fa fa-search"></i> 查詢
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Conditions",
// 使用props宣告可以使父component傳的參數
props: ["insertUrl"],
data() {
return {
conditions: {}
};
},
methods: {
searchProcess: function() {
this.$emit("searchEmit", this.conditions);
}
}
};
</script>
- Parent Component
ComponentDemo.vue
- 接收子component的
emit
事件:searchEmit
,使用v-on
的方式 - 並觸發事件時指定執行該component中的methods
searchProcess
執行後的結果 可以使用chrome偵錯視窗中的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<template>
<div id="componentdemo">
<conditions :insertUrl="insertUrl"
@searchEmit="searchProcess"></conditions>
</div>
</template>
<script>
import Conditions from "@/components/Conditions.vue";
export default {
name: "ComponentDemo",
components: {
Conditions
},
data() {
return {
insertUrl: "http://google.com.tw"
};
},
methods: {
searchProcess: function(conditions) {
console.log(conditions);
}
}
};
</script>vue
tab可以看出$emit
的歷程,也可以看出$emit
中發送的payload
- 接收子component的
動態載入
vue有提供動態載入component
的機制,若有需求是依照某些條件載入不同的component就可以使用動態載入機制。
1 | // 動態指定currentComponent的值:component名稱 |
以筆者經驗是除非有必要性,不然絕不要輕易嘗試,筆者在專案中使用的情境是,因切Layout
時,功能區塊
必須與頁面標題顯示
同個div中,頁面標題使用vue-router
中的自定義meta
屬性來宣告,因此放在layout中統一處理。
功能區塊
可以想成是取消
儲存
列印
匯出報表
等該頁面所屬功能,最後設計是每個頁面會搭配一個結尾為Feature
的頁面,會去判斷route
的值,然後指定該頁面所屬的功能列component,缺點就是Layout檔案中會有一堆component的import及宣告components
option,不過官網上的建議Automatic Global Registration of Base Components,實際範例:vue-enterprise-boilerplate或許有解,筆者目前尚未實際使用過,有機會使用後再補上心得,目前是對於動態載入component有點卻步。
結論
藉由這幾篇的觀念解說及經驗分享,筆者相信可以處理大部份的功能,經由這篇的Component介紹,就可以很有系統地去規劃頁面並重用,但傳遞資料需求上面,有父子關係才有辦法做到,但往往有系統的設計會需要無任何關係的component
間溝通,需要使用到eventbus
的技巧或vuex
的store機制,筆者會在套件介紹會寫一篇vuex
的實作,再加上會透過vue技巧
文章的方式會提出實際碰到問題時的解決方案,希望這系列文章幫助到大家。
範例檔案參考https://github.com/EugeneSu0515/VueDemoApp