在經歷了前幾篇文章的分享後,這篇文章想要整合一下前面所提到的進度,來製作一個整合性的範例,幫助大家停下腳步想想,除了每個項目分別的作用之外,有沒有什麼事可以透過這些項目的結合而產生的網頁功能,在這邊示範一個多層次的動態選單,藉以驗收學習上的成果。
下方範例有兩個下拉選單,第一個選單選擇的是Frameworks的類型,而依據類型選擇的不同,第二個選單的內容也會跟著變化,範例檔
大家可以想想看這個範例如果交到你手上,你會用什麼樣的方式來製作,建議先思考讓心中有個雛形之後,再來看看我們這邊的作法:
<div id="app">
<h3>Please select your favorite framework:</h3>
<p>
Type:
<select v-model="state.frameworksIdx">
<option v-for="(item, index) in state.frameworks" :value="index">
{{item.type}}
</option>
</select>
</p>
<p>
Name:
<select v-model="state.contentsIdx">
<option v-for="(item, index) in pickContents" :value="index">
{{item.name}}
</option>
</select>
</p>
<div class="noteText">
<p>
你選擇的框架類型是:{{ state.frameworks[state.frameworksIdx].type }} -
{{ state.frameworks[state.frameworksIdx].contents[state.contentsIdx].name }}
</p>
<p>官方網站:{{ state.frameworks[state.frameworksIdx].contents[state.contentsIdx].website }}</p>
</div>
</div>
<script>
const { reactive, computed, watch } = Vue;
const app = {
setup(){
const state = reactive({
frameworksIdx: 0, // 記錄第一層選單的被選取項目
contentsIdx: 0, // 記錄第二層選單的被選取項目
frameworks : [
{
type: 'Frontend',
contents: [
{ name: 'Vue', website: 'https://vuejs.org/' },
{ name: 'React', website: 'https://reactjs.org/' },
{ name: 'Angular', website: 'https://angular.io/' },
],
},
{
type: 'Backend',
contents: [
{ name: 'Laravel', website: 'https://laravel.com/' },
{ name: 'CakePHP', website: 'https://cakephp.org/' },
{ name: 'Django', website: 'https://www.djangoproject.com/' },
{ name: 'Ruby on Rails', website: 'https://rubyonrails.org/' },
],
},
],
})
const pickContents = computed(() => {
return state.frameworks[state.frameworksIdx].contents;
})
watch(() => state.frameworksIdx, (value) =>{
state.contentsIdx = 0;
})
return { state, pickContents };
}
}
const myVue = Vue.createApp(app).mount("#app");
</script>
稍微針對上面的範例進行一些分析:
HTML:
剛好本次這個範例也應用到之前所提到多篇文章的內容,大家也可以看看是否能更換成別的做法,接下來再做一個三層式的動態選單,內容方向做了一些調整,模擬服飾店網站的選單,透過性別的選取後決定品項,透過品項的選擇,進而顯示不同產品,下面讓大家來看看成果,也順便找找有什麼可以優化的內容,範例檔
<div id="app">
<h3>Please make your decision:</h3>
<p>
Gender:
<select v-model="state.genderIdx">
<option v-for="(item, index) in state.clothes" :value="index">
{{item.gender}}
</option>
</select>
</p>
<p>
Type:
<select v-model="state.partIdx">
<option v-for="(item, index) in pickTypes" :value="index">
{{item.part}}
</option>
</select>
</p>
<p>
Product:
<select v-model="state.itemIdx">
<option v-for="(item, index) in pickParts" :value="index">
{{item.product}}
</option>
</select>
</p>
</div>
<script>
const { reactive, computed, watch } = Vue;
const app = {
setup(){
const state = reactive({
genderIdx: 0, // 記錄第一層選單的被選取項目
partIdx: 0, // 記錄第二層選單的被選取項目
itemIdx: 0, // 記錄第三層選單的被選取項目
clothes : [
{
gender: "男",
types: [
{
part: "上衣類",
contents: [
{ product: "短袖/背心" },
{ product: "長袖" },
{ product: "立領/高領" },
{ product: "針織衫" },
{ product: "休閒襯衫" },
{ product: "商務襯衫" },
{ product: "法蘭絨系列" },
{ product: "厚棉系列" },
],
},
{
part: "外套類",
contents: [
{ product: "休閒外套" },
{ product: "Fleece系列" },
{ product: "極輕羽絨" },
{ product: "極暖羽絨" },
],
},
{
part: "下身類",
contents: [
{ product: "短/七分褲" },
{ product: "九分/束口褲" },
{ product: "休閒長褲" },
{ product: "牛仔褲" },
{ product: "保暖褲" },
],
},
{
part: "家居服",
contents: [
{ product: "家居套裝" },
{ product: "家居褲" },
{ product: "家居毯" },
],
},
],
},
{
gender: "女",
types: [
{
part: "上衣類",
contents: [
{ product: "印花短T" },
{ product: "印花長T" },
{ product: "短袖/背心" },
{ product: "七分/長袖" },
{ product: "長版上衣" },
{ product: "針織衫" },
{ product: "polo衫" },
{ product: "Pima棉" },
],
},
{
part: "外套類",
contents: [
{ product: "休閒外套" },
{ product: "Fleece系列" },
{ product: "極輕羽絨" },
{ product: "極暖羽絨" },
],
},
{
part: "下身類",
contents: [
{ product: "休閒短褲" },
{ product: "七/九分褲" },
{ product: "牛仔系列" },
{ product: "寬褲系列" },
{ product: "休閒長褲" },
{ product: "裙子" },
{ product: "連身/吊帶褲" },
{ product: "緊身褲" },
{ product: "裙子" },
],
},
{
part: "洋裝",
contents: [
{ product: "洋裝" },
{ product: "家居褲" },
{ product: "吊帶裙" },
],
},
],
},
],
})
const pickTypes = computed(() => {
return state.clothes[state.genderIdx].types;
})
const pickParts = computed(() => {
return state.clothes[state.genderIdx].types[state.partIdx].contents;
})
watch(() => state.genderIdx, (value) =>{
state.partIdx = 0;
})
watch(() => state.genderIdx, (value) =>{
state.itemIdx = 0;
})
return { state, pickTypes, pickParts };
}
}
const myVue = Vue.createApp(app).mount("#app");
</script>
大部分的程式邏輯跟兩層式選單的相差不大,但可以看到Javascript從第4行~第104行並非是邏輯運算,幾乎都是在描述資料的部分,當然其中第5~7行是配合邏輯運算紀錄使用,但除此之外,純描述資料的部分就佔約100行,當然這僅僅是示範案例,真正網站的資料恐怕還會超過這個量,但通常這樣的資料,可能不是寫死在前端而是透過後端資料庫或其他方式進行提供,所以未來我們的案例也會有這個方向的考量。