- 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ật | Có trong bài |
---|---|
Vue.createApp() | Tạo app Vue |
component + props + emit | Giao tiếp giữa cha – con |
Vue Router | Chia nhiều trang (SPA) |
v-model , v-if , v-for | Giao diện động |
@submit.prevent , @click | Bắt sự kiện người dùng |
🧪 Bài tập mở rộng:
- Thêm chức năng chỉnh sửa công việc.
- Lưu danh sách công việc vào
localStorage
. - 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