Đăng nhập

BÀI 10: DỰ ÁN MINI – TODO APP (QUẢN LÝ CÔNG VIỆC)

  • Quản lý danh sách công việc (todo list)
  • Thêm, xóa, hoàn thành công việc
  • Chia trang bằng Vue Router (Home, Add Task, About)
  • Vue 3 CDN
  • Vue Router 4 CDN
  • 100% chạy trực tiếp trên trình duyệt (không cần cài đặt)

Demo giao diện học: (1 file HTML, chia nhiều trang)

<!DOCTYPE html>
<html lang="vi">
<head>
  <meta charset="UTF-8">
  <title>Todo App - Vue 3</title>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <script src="https://unpkg.com/vue-router@4"></script>
  <style>
    body {
      font-family: Arial;
      padding: 20px;
      max-width: 700px;
      margin: auto;
    }
    nav a {
      margin-right: 15px;
      text-decoration: none;
      color: blue;
    }
    nav a.router-link-exact-active {
      font-weight: bold;
      color: darkgreen;
    }
    .todo {
      display: flex;
      justify-content: space-between;
      background: #f9f9f9;
      padding: 10px;
      margin-bottom: 8px;
      border-radius: 5px;
    }
    .todo.done {
      text-decoration: line-through;
      color: gray;
    }
    button {
      margin-left: 10px;
    }
    input[type="text"] {
      padding: 5px;
      width: 80%;
    }
  </style>
</head>
<body>

<div id="app">
  <h2>📝 Ứng dụng Todo App</h2>
  <nav>
    <router-link to="/">🏠 Trang chủ</router-link>
    <router-link to="/add">➕ Thêm công việc</router-link>
    <router-link to="/about">ℹ️ Giới thiệu</router-link>
  </nav>

  <router-view></router-view>
</div>

<script>
const Home = {
  props: ['todos'],
  emits: ['toggle-task', 'delete-task'],
  template: `
    <div>
      <h3>📋 Danh sách công việc:</h3>
      <div v-if="todos.length === 0">Chưa có công việc nào.</div>
      <div v-for="(todo, index) in todos" :key="index" :class="['todo', { done: todo.done }]">
        <span @click="$emit('toggle-task', index)">
          ✅ {{ todo.text }}
        </span>
        <button @click="$emit('delete-task', index)">❌ Xóa</button>
      </div>
    </div>
  `
};

const Add = {
  emits: ['add-task'],
  data() {
    return {
      newTask: ''
    };
  },
  template: `
    <div>
      <h3>➕ Thêm công việc mới</h3>
      <form @submit.prevent="$emit('add-task', newTask); newTask='';">
        <input type="text" v-model="newTask" placeholder="Nhập công việc..." required>
        <button type="submit">Thêm</button>
      </form>
    </div>
  `
};

const About = {
  template: `
    <div>
      <h3>ℹ️ Giới thiệu</h3>
      <p>Đây là ứng dụng quản lý công việc đơn giản, được xây dựng bằng Vue 3.</p>
      <p>Áp dụng: component, props, emit, v-model, Vue Router...</p>
    </div>
  `
};

const routes = [
  { path: '/', component: Home, props: true },
  { path: '/add', component: Add },
  { path: '/about', component: About }
];

const router = VueRouter.createRouter({
  history: VueRouter.createWebHashHistory(),
  routes
});

const app = Vue.createApp({
  data() {
    return {
      todos: [
        { text: 'Học Vue', done: false },
        { text: 'Xây Todo App', done: true }
      ]
    };
  },
  methods: {
    addTask(task) {
      if (task.trim()) {
        this.todos.push({ text: task.trim(), done: false });
      }
    },
    toggleTask(index) {
      this.todos[index].done = !this.todos[index].done;
    },
    deleteTask(index) {
      this.todos.splice(index, 1);
    }
  }
});

app.use(router);

// Lắng nghe sự kiện emit giữa component con – cha
app.component('router-view', {
  template: `<component :is="$route.component"
                        v-bind="$route.props && $route.props.default ? $route.props.default({ todos: $root.todos }) : {}"
                        @add-task="$root.addTask"
                        @toggle-task="$root.toggleTask"
                        @delete-task="$root.deleteTask"
            ></component>`
});

app.mount('#app');
</script>

</body>
</html>
Kỹ thuậtCó trong bài
Vue.createApp()Tạo app Vue
component + props + emitGiao tiếp giữa cha – con
Vue RouterChia nhiều trang (SPA)
v-model, v-if, v-forGiao diện động
@submit.prevent, @clickBắt sự kiện người dùng

🧪 Bài tập mở rộng:

  1. Thêm chức năng chỉnh sửa công việc.
  2. Lưu danh sách công việc vào localStorage.
  3. Tạo bộ lọc: tất cả / đã làm / chưa làm.

Tổng kết:

Bạn đã hoàn thiện một ứng dụng Todo App chuẩn Vue 3. Đây là nền tảng quan trọng để phát triển app phức tạp hơn như:

  • Blog cá nhân
  • App bán hàng
  • Hệ thống quản lý

Thảo luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Đăng ký nhận tin mới

Nhận bài học, tài nguyên và cơ hội việc làm qua email hàng tuần.

Chúng tôi cam kết không spam. Bạn có thể hủy bất cứ lúc nào.