2025-01-31- JavaScript 系列八:第5課 ── 體重追蹤應用程式-步驟05

2025-01-31- JavaScript 系列八:第5課 ── 體重追蹤應用程式-步驟05

下面是 **整合 Chart.js(CDN 版本)圖表功能的完整 weightTrackerApp.vue**。你只需要:

✅ 第一步:在 public/index.html 加入 CDN

請在你的專案 public/index.html 中加入 Chart.js 的 CDN:

1
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

✅ 第二步:使用以下整合好的 weightTrackerApp.vue 程式碼

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<!-- weightTrackerApp.vue -->
<template>
<div class="p-4 max-w-md mx-auto">
<h1 class="text-2xl font-bold mb-4">體重追蹤器</h1>

<!-- 輸入表單-->
<form @submit.prevent="addRecord" class="space-y-2 mb-4">
<div>
<label>日期:</label>
<input type="date" v-model="newRecord.date" />
</div>
<div>
<label>體重(kg):</label>
<input type="number" v-model.number="newRecord.weight" class="border px-2 py-1" required />
</div>
<button type="submit" class="bg-blue-500 text-white px-4 py-1 rounded">新增</button>
</form>

<!-- 清單-->
<ul class="space-y-2 mb-6">
<li v-for="(record, index) in sortedRecords" :key="record.id" class="flex justify-between items-center border p-2">
<span>{{ record.date }} - {{ record.weight }}kg</span>
<button @click="deleteRecord(record.id)" class="text-red-500">刪除</button>
</li>
</ul>

<!-- 圖表 -->
<canvas ref="chartCanvas" class="w-full h-64"></canvas>
</div>
</template>

<script setup>
import { ref, computed, onMounted, watch, nextTick } from 'vue'

const newRecord = ref({
date: '',
weight: null,
})

const records = ref([])

// 取得 chart DOM 元素
const chartCanvas = ref(null)
let weightChart = null

// 初始化資料
onMounted(() => {
const saved = localStorage.getItem('weight-records')
if (saved) {
records.value = JSON.parse(saved)
}
renderChart()
})

// 監看資料變化自動存入 localStorage 並更新圖表
watch(records, (newVal) => {
localStorage.setItem('weight-records', JSON.stringify(newVal))
nextTick(() => renderChart())
}, { deep: true })

const addRecord = () => {
if (!newRecord.value.date || !newRecord.value.weight) return
records.value.push({
id: Date.now(),
date: newRecord.value.date,
weight: newRecord.value.weight,
})
newRecord.value = { date: '', weight: null }
}

const deleteRecord = (id) => {
records.value = records.value.filter(r => r.id !== id)
}

const sortedRecords = computed(() => {
return [...records.value].sort((a, b) => new Date(a.date) - new Date(b.date))
})

const renderChart = () => {
if (!chartCanvas.value) return

// 銷毀舊圖表
if (weightChart) {
weightChart.destroy()
}

const data = sortedRecords.value
weightChart = new Chart(chartCanvas.value, {
type: 'line',
data: {
labels: data.map(r => r.date),
datasets: [{
label: '體重 (kg)',
data: data.map(r => r.weight),
borderColor: 'rgba(59,130,246,1)',
backgroundColor: 'rgba(59,130,246,0.2)',
fill: true,
tension: 0.2
}]
},
options: {
responsive: true,
plugins: {
title: {
display: true,
text: '體重變化圖'
}
},
scales: {
y: {
beginAtZero: false
}
}
}
})
}
</script>

這樣就完成整合了!

✅ 圖表會根據輸入資料自動更新
✅ 使用 Chart.js CDN,不需安裝
✅ 排序、刪除、儲存都保留原有功能