# 08. 互動式資料表單
像選擇縣市地區的資料連動選單:
# 摘要
- 改變資料結構:將依天排序的資料,改為依類型排序的巢狀結構。
- 產生第一層選單 (type):顯示所有類別。
- 產生第二層選單 (title):依據選擇的類別列出標題。
- 在下方顯示篩選後文字內容:依據選擇的標題顯示其內容。
# 改變資料結構
這個單元的 input
用來進行巢狀資料篩選。原本的資料是以天排列的,因此要先改變資料結構,讓資料成為如下的巢狀結構:
類型 (type)
└ 標題 (title)
├ 連結 (link)
└ 天數 (index)
首先,資料結構的改變使用 Vue 的computed
。
typeList() {
let obj = {
sort: [], // 儲存排序。
map: {} // 儲存對應表 (每個 type 裡面對應的內容)。
}
this.menu.forEach((item, index) => {
let {type, title, link} = item
// 將沒出現過的 type 初始化,以便後面塞資料。
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, link };
})
return obj
},
# 產生第一層選單 (type)
在 Vue data
建立 input
,裡面的 type
和 title
預設值為 null
。
data = {
input: {
type: null,
title: null
}
}
然後將 typeList
的資料綁定到選單。
<select v-model="input.type">
<!-- 這裡的 null 因為被綁定,因此被當作空的程式 -->
<option :value="null">請選擇</option>
<option v-for="item in typeList.sort">{{ item }}</option>
</select>
# 產生第二層選單 (title)
當我們從 input
選擇了一個 type
,要回傳 typeList
中對應的 title
清單,沒有的話就回傳空陣列。透過 computed
來產生第二層資料的清單:
titleList() {
this.input.title = null; // 先清空 input.title 的值
if (this.input.type) {
return this.typeList.map[this.input.type];
} else {
return [];
}
},
要注意的是,假設先選了 「風味沙拉」 和裡面的 「CSS 與 jQuery 動畫」,再重新去選「用餐插曲」,會發現 title
選單變成一片空白。這是因為剛才選的 input.title
的值還在,但是新的 input.type
裡面沒有這個值,才導致 bug 出現。
解決方式是,每次選擇 input.type
時,都先將 input.title
的值清除,讓其值為 null
,對應 HTML 裡的 「請選擇」 選項。
# 在下方顯示篩選後文字內容
最後,依據選擇的 input.title
顯示天數跟連結。
content() {
if (this.input.title) {
return this.titleList.map[this.input.title];
} else {
return null;
}
}
本範例 HTML 的主要結構則如下:
<div class="input">
<select v-model="input.type">
<!-- 這裡的 null 因為被綁定,因此被當作空的程式 -->
<option :value="null">請選擇</option>
<option v-for="item in typeList.sort">{{ item }}</option>
</select>
<select style="width: 500px" v-model="input.title">
<option :value="null">請選擇</option>
<option v-for="item in titleList.sort">{{ item }}</option>
</select>
</div>
<div class="description">
<div class="menuItem" style="text-align: center" v-if="content">
<span class="number">{{ content.index + 1 }}</span>
<a :href="content.link" class="title">{{ content.link }}</a>
</div>
</div>
這裡的 null
因為被綁定,因此被當作空的程式。當 input.type
或 input.title
的值為 null
的時候,顯示的選項會是「請選擇」。