文章

Vue3 項目實戰:Todo 應用

在這個實戰中,我們將使用 Vue 3 構建一個簡單的 Todo 應用,這個應用將展示 Vue 3 的基本功能,包括 雙向數據綁定事件處理條件渲染列表渲染 以及 組件 的使用。通過這個項目,你可以熟悉 Vue 3 的核心概念和開發方式。

1. 項目結構

首先,我們將準備好 Vue 3 項目的結構。假設我們已經使用 Vue CLI 或 Vite 創建了一個 Vue 3 項目,基本目錄結構如下:

1
2
3
4
5
6
src/
│
├── components/
│   └── TodoItem.vue
├── App.vue
└── main.js

2. 應用設計

  • 功能點
    • 用戶可以新增待辦事項。
    • 用戶可以刪除待辦事項。
    • 用戶可以標記待辦事項為已完成。

3. 實現步驟

1. 主應用模板 (App.vue)

App.vue 是我們應用的主文件,我們將設置一個簡單的模板和邏輯來管理 Todo 列表。

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
<template>
  <div id="app">
    <h1>Todo List</h1>
    
    <!-- 輸入框與新增按鈕 -->
    <div>
      <input v-model="newTodo" placeholder="新增待辦事項" />
      <button @click="addTodo">新增</button>
    </div>

    <!-- 顯示 Todo 列表 -->
    <ul>
      <TodoItem
        v-for="todo in todos"
        :key="todo.id"
        :todo="todo"
        @toggleComplete="toggleComplete"
        @removeTodo="removeTodo"
      />
    </ul>
  </div>
</template>

<script>
import { ref } from 'vue';
import TodoItem from './components/TodoItem.vue';

export default {
  components: {
    TodoItem
  },
  setup() {
    const newTodo = ref('');  // 用於新增待辦事項的輸入
    const todos = ref([]);    // 用於存儲待辦事項的列表

    // 新增待辦事項
    const addTodo = () => {
      if (newTodo.value.trim()) {
        todos.value.push({
          id: Date.now(),
          text: newTodo.value.trim(),
          completed: false
        });
        newTodo.value = ''; // 清空輸入框
      }
    };

    // 切換完成狀態
    const toggleComplete = (id) => {
      const todo = todos.value.find(t => t.id === id);
      if (todo) {
        todo.completed = !todo.completed;
      }
    };

    // 刪除待辦事項
    const removeTodo = (id) => {
      todos.value = todos.value.filter(todo => todo.id !== id);
    };

    return {
      newTodo,
      todos,
      addTodo,
      toggleComplete,
      removeTodo
    };
  }
};
</script>

<style scoped>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  text-align: center;
  margin-top: 60px;
}
</style>

2. TodoItem 組件 (TodoItem.vue)

接下來,我們將創建 TodoItem.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
<template>
  <li :class="{ completed: todo.completed }">
    <input
      type="checkbox"
      :checked="todo.completed"
      @change="toggleTodo"
    />
    <span></span>
    <button @click="removeTodo">刪除</button>
  </li>
</template>

<script>
export default {
  props: {
    todo: Object
  },
  emits: ['toggleComplete', 'removeTodo'],
  setup(props, { emit }) {
    const toggleTodo = () => {
      emit('toggleComplete', props.todo.id);
    };

    const removeTodo = () => {
      emit('removeTodo', props.todo.id);
    };

    return {
      toggleTodo,
      removeTodo
    };
  }
};
</script>

<style scoped>
li {
  list-style: none;
  margin: 10px 0;
}

.completed span {
  text-decoration: line-through;
}
</style>

4. 核心功能解析

1. 新增待辦事項

在主應用 App.vue 中,通過輸入框來收集用戶的待辦事項。使用 v-model 雙向綁定輸入框的值,並在點擊「新增」按鈕時觸發 addTodo 方法,將新待辦事項加入 todos 列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
const newTodo = ref(''); // 用於輸入新的待辦事項
const todos = ref([]);   // 存儲待辦事項列表

const addTodo = () => {
  if (newTodo.value.trim()) {
    todos.value.push({
      id: Date.now(),          // 生成唯一 ID
      text: newTodo.value.trim(), // 待辦事項內容
      completed: false         // 初始化為未完成狀態
    });
    newTodo.value = ''; // 清空輸入框
  }
};

2. 切換完成狀態

每個待辦事項都有一個勾選框,當用戶點擊它時會觸發 toggleComplete 事件,該事件將更新待辦事項的 completed 狀態。

1
2
3
4
5
6
const toggleComplete = (id) => {
  const todo = todos.value.find(t => t.id === id); // 根據 ID 查找待辦事項
  if (todo) {
    todo.completed = !todo.completed; // 切換狀態
  }
};

TodoItem 組件中,我們使用 @change="toggleTodo" 綁定切換事件,並透過 emit 向父組件傳遞事件:

1
2
3
const toggleTodo = () => {
  emit('toggleComplete', props.todo.id); // 向父組件傳遞事件
};

3. 刪除待辦事項

每個待辦事項旁邊都有一個「刪除」按鈕,點擊時會觸發 removeTodo 事件,該事件將待辦事項從 todos 列表中移除。

1
2
3
const removeTodo = (id) => {
  todos.value = todos.value.filter(todo => todo.id !== id); // 過濾掉要刪除的待辦事項
};

TodoItem 中,我們使用 @click="removeTodo" 綁定刪除事件,同樣透過 emit 向父組件傳遞事件:

1
2
3
const removeTodo = () => {
  emit('removeTodo', props.todo.id); // 向父組件傳遞事件
};

5. 樣式處理

我們使用簡單的樣式來美化應用,特別是 completed 狀態下,將已完成的待辦事項添加刪除線:

1
2
3
.completed span {
  text-decoration: line-through;
}

6. 總結

通過這個簡單的 Todo 應用,我們實現了以下 Vue 3 的核心功能:

  • 雙向數據綁定 (v-model)
  • 事件處理 (@click, @change)
  • 列表渲染 (v-for)
  • 條件渲染與狀態管理 (completed 狀態)
  • 組件通信(使用 propsemit

這個應用還可以進一步擴展,例如添加本地存儲功能、編輯待辦事項、過濾完成與未完成事項等。希望這個實戰能夠幫助你熟悉 Vue 3 的基本概念和使用方法。

本文章以 CC BY 4.0 授權