:::info
本文件連結:https://hackmd.io/3nx1b0V3RV-KCNHGWftH_g
此為 2025 Vue3 前端新手營課程資料,相關資源僅授權給該課程學員。
:::
# 第二週:Vue Composition API,方法、監聽與 AJAX
## 課前說明
- 每日任務:Discord 上發布
- 每週挑戰:
- 一~三週:HackMD 上繳交
- 最後一週作業
- RPG 程式勇者:
- 課程捷徑
- 課程講義
- 最後一週作業繳交
- 提醒老師錄影
## 課綱核心
- 複習,指令
- Methods、Computed、Mounted 常見技巧
- Async Function
## 上半場要做的架構

## 建立環境
```
npm create vite@latest
```
## 複習與指令
完成一個 CRUD 的範例
## Mounted、Computed

### Mounted

- 關於生命週期:https://cn.vuejs.org/guide/essentials/lifecycle.html
- 關於 Mounted 來說:
- 最常用到的生命週期
- 可以作為**初始化事件**(例如 Ajax 取得第一筆資料)
- 在此生命週期後,才能抓到 DOM 元素
- 可以重複使用
### Computed
- 自動監聽
- 可以產出一個新的結果,僅能讀取,不能寫入
- 主要用途為顯示在畫面上(HTML)
- 不能寫入其他的值

除此之外,還有…
- Watch
- WatchEffect 等方法
## Async Function
本課程會使用 Axios 套件進行呼叫
1. 為什麼要用 Promise、Async/Await(本課程都是以 Async/Await 為主
2. Async/Await 實戰運用方法
3. Async function 的錯誤處理
4. Vue 中使用 Async Function
1. onMounted 中使用
2. 主動呼叫
## 課程 API 串接
API 文件:https://todolist-api.hexschool.io/doc/
Cookie 文件:https://developer.mozilla.org/zh-CN/docs/Web/API/Document/cookie

## 作業

Todo List API
參考課程 API,完成 TodoList 串接:https://todolist-api.hexschool.io/doc/#/
- Level 1:完成所有功能的串接
- Level 2:嘗試套版,版型不限(單頁完成)
解答連結:
- 執行範例:https://www.casper.tw/2024-vue-homework/#/week2
- 原始碼:https://github.com/Wcc723/2024-vue-homework/blob/main/src/views/Week2View.vue
- 作業繳交連結:https://hackmd.io/GaHyBZ0nR-6-Z7s6zbXQhA
### 預告
最終任務:
- 設計稿:https://www.figma.com/design/MFSk8P5jmmC2ns9V9YeCzM/TodoList?node-id=0-1&t=KzEgeE3s3r6JIPh6-1
- CSS 範例:https://codepen.io/hexschool/pen/qBzEMdm
- 同時挑戰證書任務:
- 最終挑戰 - Todolist 新手證書任務
- 最終挑戰 - Todolist API 整合證書任務
### 上半場範例
::: spoiler
```
<template>
<h1>複習</h1>
<div>
<input type="text" v-model="newName">
{{ newName }}
<input type="text" v-model="newNumber">
{{ newNumber }}
<button type="button" @click="addProduct">
新增到資料集裡面
</button>
</div>
<table>
<thead>
<tr>
<th>標題</th>
<th>價格</th>
<th>調整價格</th>
<th>刪除</th>
</tr>
</thead>
<tbody>
<tr v-for="item in data" :key="item.id">
<td>{{ item.name }}</td>
<td>{{ item.price }}</td>
<td><input type="number" v-model="item.price"></td>
<td>
<button type="button" @click="delItem(item.id)">刪除品項</button>
</td>
</tr>
</tbody>
</table>
</template>
<script setup>
import { ref } from "vue";
const newName = ref('');
const newNumber = ref(0);
const data = ref([
{ id: 1, name: "珍珠奶茶", price: 50 },
{ id: 2, name: "冬瓜檸檬", price: 45 },
{ id: 3, name: "翡翠檸檬", price: 55 },
{ id: 4, name: "四季春茶", price: 45 },
{ id: 5, name: "阿薩姆奶茶", price: 50 },
{ id: 6, name: "檸檬冰茶", price: 45 },
{ id: 7, name: "芒果綠茶", price: 55 },
{ id: 8, name: "抹茶拿鐵", price: 60 }
])
const addProduct= () =>{
console.log("addProduct")
data.value.push({
id: new Date().getTime(),
name: newName.value,
price: newNumber.value
})
newName.value='';
newNumber.value=0;
}
const delItem =(id) =>{
console.log('delItem',id);
const index = data.value.findIndex(item=>item.id===id);
data.value.splice(index,1);
}
</script>
<style>
</style>
```
## todo
```
<template>
<h1>待辦</h1>
<h2>註冊功能</h2>
<input type="email" placeholder="Email" v-model="signupField.email">
<input type="text" placeholder="密碼" v-model="signupField.password">
<input type="text" placeholder="暱稱" v-model="signupField.nickname">
<br>
{{ signupField }}
<br>
<button type="button" @click="signup">註冊</button>
{{ signupRes }}
<h2>登入功能</h2>
<input type="email" placeholder="Email" v-model="signInField.email">
<input type="text" placeholder="密碼" v-model="signInField.password">
<br>
{{ signInField }}
<br>
<button type="button" @click="signIn">登入</button>
<br>
token:{{ signInRes }}
<h2>驗證</h2>
<div v-if="user.uid">
<p>UID:{{ user.uid }}</p>
<p>NickName:{{ user.nickname }}</p>
</div>
<div v-else>
你還沒有登入
</div>
</template>
<script setup>
import {ref,onMounted} from 'vue';
import axios from 'axios';
const api = 'https://todolist-api.hexschool.io/';
const signupField = ref({
email:'',
password:'',
nickname:''
})
const signupRes = ref('')
const signup = async()=>{
try{
const res = await axios.post(`${api}users/sign_up`,signupField.value);
console.log(res);
signupRes.value = res.data.uid
}catch(error){
console.log("錯誤!")
console.log(error)
}
}
const signInField = ref({
email:'',
password:''
})
const signInRes = ref('');
const signIn = async()=>{
try{
const res = await axios.post(`${api}users/sign_in`,signInField.value);
console.log(res);
signInRes.value = res.data.token;
document.cookie = `customTodoToken=${res.data.token};path=/`
}catch(error){
console.log("錯誤!")
console.log(error)
}
}
// 驗證
const user = ref({
nickname: '',
uid:''
})
onMounted(async()=>{
// 驗證登入
const token = document.cookie.replace(/(?:^|.*;\s*)customTodoToken\s*=\s*([^;]*).*$/i,
"$1")
const res = await axios.get(`${api}users/checkout`,{
headers:{
Authorization: token
}
})
console.log(res);
user.value= res.data;
})
</script>
<style></style>
```
:::