這一系列文章的主軸是 「需求至上」的 Vue 3 學習之旅。
我會預設大家都是有JS開發經驗的人~
本篇章主要是把每個實戰按理當作說書的方式來執行
我不會逐條講解 API,而是用 「需求 → user story/data schema/ flow → 對應的 Vue 功能」 的方式,讓每一篇文章都從真實需求開始,經過邏輯推導與系統設計,最後自然帶出 Vue 的寫法與觀念。
整個系列分成多個 Chapter
每一個 Chapter 就像一個小型專案或情境任務。
第一個 Chapter 是 「點飲料系統」:我們會從一杯飲料的最小需求出發,一步步加入事件處理、輸入驗證、樣式綁定、訂單統計,並同時建立對 ** v-if、v-model、@click、:class、reactive** 等 Vue 核心能力的深刻理解。
Day | 標題 | 核心學習內容 |
---|---|---|
Day 1 | 從「這不是我要的」開始:流程圖推導到 v-if 與 :disabled |
只處理「紅茶/綠茶」與「甜度、冰量」的基本判定。學會 v-if 、:disabled ,並用需求驅動狀態 ref 與 onchange 。 |
Day 2 | 事件觸發的本質:為什麼需要 @click 才能把使用者行為轉成狀態 |
加入「送出」事件。理解 @click 與方法綁定,完成點餐資料的第一次儲存。 |
Day 3 | 輸入框的需求:v-model 背後的雙向資料流思維 |
引入使用者姓名與備註輸入框,深入理解 v-model 與雙向資料流。 |
Day 4 | 為什麼需要資料綁定?用「狀態→樣式」引出 :class |
根據訂單狀態自動切換樣式,例如完成下單後改變背景或標籤顏色。 |
Day 5 | 系統需求:清單管理 → reactive 陣列 → 新增/刪除/統計 |
管理多筆飲料訂單,用 reactive 陣列彙總、刪除、統計每種客製化飲品的數量。 |
** 在 Part 1 結束時,我們會擁有一個能 完整輸入、送出並統計飲料訂單 的前端小系統。 **
我需要一個網頁表單可以讓使用者填寫想喝的飲料、客製化(糖/冰),統計完後統計者(秘書)可以自動計算「飲料 + 客製化」的每種組合數量。
今日僅做選項判定與摘要顯示;統計會在 Part 1 後續章節完成。
規格限制(今日版)
飲料:紅茶、綠茶
甜度:正常甜、去糖
冰量:正常冰、去冰
今天的目標大概是這樣的進度
我的今天的流程控制
會先一關一關選
例如選惹飲料沒選甜度的UI會長這樣
都選完了會長這樣
我們會先把整個vue的框架架構簡單講解出來
首先我們採用的是VUE SFC的架構(以後component架構再講,先操表就對了!!)
vue有一個最基礎的型態它裡面可以寫
<template>
</template>
HTML TAG
像 <h2>、<fieldset>、<label>、<input>、<button>
Vue 語法糖:
判斷條件:drink && sweetness
在 JavaScript 中,「字串」如果不是空字串就算 true。
A && B 代表:A 與 B 都必須為真。
作用:只有當 drink 和 sweetness 都有值 時,才會渲染這個 。
流程上的意思:
使用者 至少選了飲料 → 甜度選項出現。
使用者 同時選了飲料和甜度 → 冰量選項才出現。
屬性綁定::disabled="!canSubmit"
→ : 是 v-bind 的簡寫,把 JS 的布林值綁到 HTML 屬性。
事件綁定:@change="onDrinkChange('紅茶')"
→ @ 是 v-on 的簡寫,用來綁定事件並呼叫方法。
用途:監聽元素的 change 事件。
change 是瀏覽器的標準事件,表示輸入內容改變。
在 script setup 內,我們用:
插值語法:{{ drink }}
→ 顯示對應的 JavaScript 變數值。
computed(() => drink.value && sweetness.value && ice.value)
這是一個根據其他狀態自動運算的值。
只有當 drink、sweetness、ice 都有值時,這個運算式才為 true。
可以把它例解釋自動判定的計算機
<script setup>
import { ref, computed } from 'vue'
const drink = ref('')
const sweetness = ref('')
const ice = ref('')
function onDrinkChange(value) { drink.value = value }
function onSweetnessChange(value) { sweetness.value = value }
function onIceChange(value) { ice.value = value }
const canSubmit = computed(() => drink.value && sweetness.value && ice.value)
</script>
使用 setup 語法糖,不需要 export default 或 data()、methods,程式更精簡。
在 script setup 內宣告的變數與方法,可以直接在 template 中使用。
ref(''):宣告可以響應的變數(drink、sweetness、ice),初始值為空字串。
三個 onXXXChange():接收使用者點選的值並更新狀態。
computed:自動計算出 canSubmit,只有三個選項都選了才會是 true。
<template>
<h2>飲料點單(Day 1)</h2>
<!-- 步驟 1:飲料 -->
<fieldset>
<legend>步驟 1:選擇飲料</legend>
<label>
<input type="radio" name="drink" value="紅茶" @change="onDrinkChange('紅茶')"> 紅茶
</label>
<label>
<input type="radio" name="drink" value="綠茶" @change="onDrinkChange('綠茶')"> 綠茶
</label>
<p v-if="!drink">⚠️ 尚未選取飲料</p>
<p v-else>✅ 已選:{{ drink }}</p>
</fieldset>
<!-- 步驟 2:甜度(只在選好飲料後顯示) -->
<fieldset v-if="drink">
<legend>步驟 2:選擇甜度</legend>
<label>
<input type="radio" name="sweetness" value="正常甜" @change="onSweetnessChange('正常甜')"> 正常甜
</label>
<label>
<input type="radio" name="sweetness" value="去糖" @change="onSweetnessChange('去糖')"> 去糖
</label>
<p v-if="!sweetness">⚠️ 尚未選擇甜度</p>
<p v-else>✅ 已選:{{ sweetness }}</p>
</fieldset>
<!-- 步驟 3:冰量(只在選好甜度後顯示) -->
<fieldset v-if="drink && sweetness">
<legend>步驟 3:選擇冰量</legend>
<label>
<input type="radio" name="ice" value="正常冰" @change="onIceChange('正常冰')"> 正常冰
</label>
<label>
<input type="radio" name="ice" value="去冰" @change="onIceChange('去冰')"> 去冰
</label>
<p v-if="!ice">⚠️ 尚未選擇冰量</p>
<p v-else>✅ 已選:{{ ice }}</p>
</fieldset>
<!-- 送出按鈕與摘要 -->
<button :disabled="!canSubmit">送出</button>
<p v-if="canSubmit">
你的選擇:{{ drink }} / {{ ice }} / {{ sweetness }}
</p>
</template>
<script setup>
import { ref, computed } from 'vue'
// 儲存使用者選擇
const drink = ref('')
const sweetness = ref('')
const ice = ref('')
// 逐步事件處理
function onDrinkChange(value) {
drink.value = value
}
function onSweetnessChange(value) {
sweetness.value = value
}
function onIceChange(value) {
ice.value = value
}
// 全部完成才能送出
const canSubmit = computed(() => drink.value && sweetness.value && ice.value)
</script>
完成後我們就可以驗證是否完成!!
我們可以根據使用者情境一關一關點餐完成飲料的系統
明天再繼續完成這個系統吧!!!