
這個其實蠻常看到的,最常出現是在透過縣市選擇區域, 例如說先點選新北市, 再從新北市各分區裡面挑一個, 例如說新店區爾爾. 通常拿到的可能是一般陣列裡面包著物件的格式, 因此底下就在敘述如何改變資料的結構.
資料結構
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
| menu: [ { type: '私房小物', title: 'Zippo打火機', }, { type: '私房小物', title: '台灣菸酒公司紀念狀', }, { type: '最美的地方', title: '山頂上', }, { type: '最美的地方', title: '西湖河畔', }, { type: '鼎泰豐', title: '小籠包', }, { type: '私房小物', title: '3231股票一張', }, { type: '鼎泰豐', title: '粒粒分明炒飯', }, ],
|
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
| { "sort": [ "私房小物", "最美的地方", "鼎泰豐" ], "map": { "私房小物": { "sort": [ "Zippo打火機", "台灣菸酒公司紀念狀", "3231股票一張" ], "map": { "Zippo打火機": { "index": 0 }, "台灣菸酒公司紀念狀": { "index": 1 }, "3231股票一張": { "index": 5 } } },
|

要改成上述的結構,可以看到會由obj裡面包含兩種資料型態. 一種是陣列, 一種是物件
- 陣列的部分, 是比較簡單的, 因為是要做排序, 所以以sort為名稱, 裡面放入type.
- 物件的部分, 是層層疊疊的形式, 所以以map為名稱, 而map裡面藏有以title命名的物件.
可以看到資料是有層疊關係的, 因為有私房小物, 所以展開私房小物有三項, 而每一項又可以展開index.
暖身練習
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var auntie = { name: '陳小美', ages: 22, bwh: { strength: 34, agility: 25, intelligence: 96 }, single: true };
auntie.bwh["strength"] auntie.bwh["xxx"] auntie.bwh["xxx"] = 123 console.log(auntie)
|
1 2 3 4 5 6 7
| { bwh: strength: 34 agility: 25 intelligence: 96 xxx: 123 }
|
可以看到把xxx加入變成key值, 並且加入123這個value
實戰部分
記得已經知道目前想要的資料結構, 那就來寫寫看吧!
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
| typeList(){ let obj = { sort: [], map: {} } this.menu.forEach((item, index) => { let {type, title} = {item} if(!obj.map[type]){ obj.sort.push(type)
obj.map[type] = { sort: [], map: {} }
obj.map[type].sort.push(title)
obj.map[type].map[title] = {index} } }) return obj }
|
這要真得很了解物件的結構才會做得出來.
外部資源參考
這邊來推薦下這個網站, 可以把資料轉成比較好理解的格式.
基本上很簡單, 只要在Vue devtool裡面點選 => 點點點, 就可以貼在這個網站的text在裡面
正確的作法是改成底下的資料結構形式, 這樣就很直覺了
select 表單
程式結束以後, 來看下畫面的部分.
- 第一個下拉式選單, 在select標籤綁定全域的資料input.type並且與option :value中的item對應
- 第二個下拉式選單, 在select標籤綁定全域的資料input.title並且透過第一個下拉式選單type, 得知與之對應的title.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <select name="" id="" v-model="input.type" > <option :value="null">請選擇</option> <option v-for="item in typeList.sort" :value="item" >{{item}}</option> </select>
<select name="" id="" v-model="input.title" > <option :value="null">請選擇</option> <option :value="item" v-for="item in titleList.sort" >{{item}}</option> </select>
|
titleList實作
1 2 3 4 5 6 7 8 9 10 11
| titleList(){ this.input.title = null
if(this.input.type){ return this.typeList.map[this.input.type] }else{ return [] } }
|
畫面渲染
通常兩個連動的select都選擇完後, 就會有相對應的畫面.
這邊是以顯示index為例.
這個時候還要再用一個computed
把資料彙整出來
1 2 3 4 5 6 7 8
| content(){ if(this.input.title){ return this.titleList.map[this.input.title] }else{ return null } }
|
v-if 細節注意
因為content是要等到, titleList也被選起的時候才會渲染出index.
所以這邊要下一個v-if, 當有content的時候, 才去content return回來的陣列找出index
1 2 3
| <div class="number" style="font-size:32px; margin-left:10px;" v-if="content">{{content.index + 1}} </div>
|
總結
現在這樣乍看突然覺得層級好分明.
因為要做到渲染, 所以sort是專門給v-for所使用. 而map裡面的type是要與sort的type相對應的.
後記 - 不改變資料結構的作法
現在想到另外一種方法, 但是這個只有在vue裡面才有作用, 這個filter就是e.target.value
, 要和item中county值相同
但是問題是, 現在這個item.properties.county
這不是單一值….
1 2 3 4 5 6 7 8
| vm.dataAry.forEach(item => { if (vm.filter === item.properties.county){ vm.townFilter.push(item.properties.town) }else{ console.log(123) } })
|
所以我想到的方法是透過陣列的find
方法
會回傳第一個滿足所提供之測試函式的元素值`, 這樣回傳的就是單一值, 而不是回傳一堆一樣的東西
圖示如下
1 2
| forEach => '新北市' === '新北市*100' find => '新北市' === '新北市'
|
節錄最後連動資料, 所運行的程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| vm.town.length = 0
vm.dataAry.find(item => { if (vm.select.filter === item.properties.county){ vm.town.push(item.properties.town) } }) vm.townFilter = vm.town.filter((item, index, arr) => { return vm.town.indexOf(item) === index; });
return vm.dataAry.filter(item => { return item.properties.county == vm.select.filter && item.properties.town == vm.select.filter2 });
|