[Vue] - (九)自訂事件 Custom Events-實作

本篇主要是透過線上課程:HiSKIO、及網路上搜尋資源所學習的。

實作-鄉鎮市區下拉選單

分為兩個下拉選單,第一個下拉選單是選擇縣市,第二個選單則是區域。
選擇後要顯示選擇到的縣市跟區域並帶有郵遞區號。

組件命名,如果是用 template ,不是用 html 的話,是不限於大小寫限制的。

用 select 來選擇,Vue 實例中的 template 模板直接用大寫組件名稱Select
V-model 綁定 cityIndex (等於 select 中的 value ,所以在下層Select組件中 props 有一個 value 以已經綁定這個值), v-bind 綁定 options=”cities”,這裡的 cities 是 data 中的 cities ,這邊用 computed 來計算並回傳宣告的 cities 物件。

下層 Select 組件中,要有 props 的屬性 value 跟 options 以外, template 中 select v-model 這邊如果是綁定 value 的話,是無法透過 select 後把 value 傳到上層,需要透過 computed 來計算 並用 set 來發出 $emit 事件。

  • 組件的 v-model 不能修改 this 的 props (但可以透過 computed 來計算)
    computed 用物件表達並用 index 命名後,用 get 取得目前 value , set 則把目前值用 $emit(‘input’) 的上層去。
    上層則是 v-model 的 cityIndex 接收到值。

再來在上層 template 新增一組區域的 Select ,並在 computed 中去執行 areas 的計算獲取宣告的陣列中的區域, zip 則是獲取郵遞區號。
這邊會遇到如果切換的時候,不同 city 在切換時,會因為有不同 index 的 area 導致可能會顯示異常,這邊會用 watch 來偵聽,一旦 cityIndex 切換的時候就把 areaIndex 歸零。

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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
<div id="app"></div>

<script>
const cities = [{
name: '台北市',
areas: [{
name: '中正區',
zip: '100'
},
{
name: '大同區',
zip: '103'
},
{
name: '中山區',
zip: '104'
},
{
name: '松山區',
zip: '105'
},
{
name: '信義區',
zip: '110'
},
{
name: '南港區',
zip: '115'
},
],
},
{
name: '新北市',
areas: [{
name: '板橋區',
zip: '220'
},
{
name: '三重區',
zip: '241'
},
{
name: '永和區',
zip: '234'
},
{
name: '中和區',
zip: '235'
},
{
name: '新店區',
zip: '231'
},
{
name: '新莊區',
zip: '242'
},
],
},
{
name: '新竹市',
areas: [{
name: '新竹市',
zip: '300',
}],
},
{
name: '彰化縣',
areas: [{
name: '彰化市',
zip: '500'
},
{
name: '秀水鄉',
zip: '504'
},
{
name: '花壇鄉',
zip: '503'
},
{
name: '鹿港鎮',
zip: '505'
},
{
name: '員林鎮',
zip: '510'
},
{
name: '溪湖鎮',
zip: '514'
},
],
},
];
Vue.component('Select', {
props: ['value', 'options'],
computed: {
index: {
get() {
return this.value;
},
set(val) {
this.$emit('input', val);
},
},
},
// select v-model 不能直接綁定上層傳來的 value ,因為無法改動上層的index,可以用 computed set 來發送事件達成
template: `
<select v-model="index">
<option v-for="(item, index) in options" :value="index">{{item.name}}</option>
</select>
`
}),
new Vue({
el: '#app',
data: {
cityIndex: 0,
areaIndex: 0,
},
computed: {
cities() {
// return 外層宣告的 cities
return cities;
},
areas() {
return cities[this.cityIndex].areas;
},
zip() {
return this.areas[this.areaIndex].zip;
}
},
watch: {
cityIndex() {
this.areaIndex = 0;
},
},
template: `
<div>
<h1>County</h1>
{{cityIndex}}
<Select v-model="cityIndex" :options="cities"></Select>
<Select v-model="areaIndex" :options="areas"></Select>
</br>
{{cityIndex}} - {{areaIndex}} - {{zip}}
</div>
`
})
</script>