1. Vue Lifecycle Hooks – Vòng đời của một Component
Vue cung cấp các "hooks" giúp bạn thực hiện hành động tại các giai đoạn khác nhau của vòng đời component.
export default { data() { return { message: 'Xin chào Vue!' }; }, created() { console.log('Component đã được tạo (created)'); }, mounted() { console.log('Component đã gắn vào DOM (mounted)'); }, destroyed() { console.log('Component đã bị hủy (destroyed)'); }
}
📌 Giải thích:
created()
: Chạy sau khi component được khởi tạo, chưa render ra DOM.mounted()
: Chạy sau khi component đã được mount vào DOM.destroyed()
: Chạy khi component bị hủy.
2. Vue Router – Routing trong SPA (Single Page Application)
Vue Router là một thư viện chính thức của Vue.js giúp bạn tạo ứng dụng nhiều trang (SPA) mà không cần tải lại trang (reload). Khi bạn chuyển giữa các "trang", Vue Router sẽ thay đổi URL và hiển thị component tương ứng mà không làm trình duyệt reload.
SPA = Single Page Application: chỉ có 1 file HTML, nhưng giao diện nhiều phần như "trang chủ", "giới thiệu", "liên hệ", v.v.
2.1 Cài đặt:
Nếu bạn dùng dự án Vue CLI:
npm install vue-router
2.2 Cấu hình Vue Router:
Bạn cần tạo một file riêng để định nghĩa các route (đường dẫn), ví dụ: router.js
Bước 1: Tạo các Component
dùng làm trang
// Home.vue <template> <div> <h2>Trang chủ</h2> <p>Chào mừng bạn đến với Vue!</p> </div>
</template>
// About.vue <template> <div> <h2>Giới thiệu</h2> <p>Đây là trang giới thiệu về ứng dụng.</p> </div>
</template>
Bước 2: Tạo file router.js
// router.js import Vue from 'vue';
import VueRouter from 'vue-router'; import Home from './components/Home.vue';
import About from './components/About.vue'; Vue.use(VueRouter); // Kích hoạt plugin const routes = [ { path: '/', component: Home }, { path: '/about', component: About }
]; const router = new VueRouter({ mode: 'history', // Dùng history API (không có hash #) routes
}); export default router;
📌Giải thích:
- path: Đường dẫn URL.
- component: Component sẽ hiển thị khi truy cập vào path đó.
- mode: 'history': Giúp URL trông đẹp hơn, bỏ dấu #.
Bước 3: Tích hợp router vào Vue
// main.js import Vue from 'vue';
import App from './App.vue';
import router from './router'; new Vue({ router, render: h => h(App),
}).$mount('#app');
2.3 Điều hướng và hiển thị component
Trong App.vue:
<template> <div> <h1>Ứng dụng Vue Router</h1> <nav> <router-link to="/">Trang chủ</router-link> | <router-link to="/about">Giới thiệu</router-link> </nav> <router-view></router-view> </div>
</template>
📌 Giải thích:
<router-link>
: Thẻ dùng để điều hướng (giống<a>
nhưng không reload trang).to="/"
: Đường dẫn tương ứng vớiroute
.<router-view>
: Nơicomponent
được hiển thị tương ứng vớiroute
đang truy cập.
2.4 Điều hướng bằng JavaScript
Bạn có thể điều hướng bằng code:
this.$router.push('/about');
Hoặc quay lại:
this.$router.go(-1);
2.5 Dynamic Route (Route có tham số)
Bước 1: Tạo component User.vue
// User.vue <template> <div> <h2>Trang người dùng</h2> <p>Đây là người dùng có ID: {{ userId }}</p> </div>
</template> <script>
export default { computed: { userId() { // Lấy giá trị id từ route param return this.$route.params.id; } }
}
</script>
📌 Giải thích:
this.$route.params.id
: lấy giá trị id từ URL.- Dùng
computed
để hiển thịuserId
mỗi khi URL thay đổi.
Bước 2: Cập nhật router
// router.js import Vue from 'vue';
import VueRouter from 'vue-router';
import User from './components/User.vue';
import Home from './components/Home.vue'; Vue.use(VueRouter); const routes = [ { path: '/', component: Home }, { path: '/user/:id', component: User } // Route có tham số
]; const router = new VueRouter({ mode: 'history', routes
}); export default router;
📌 Giải thích:
:id
là tham số động. Bạn có thể dùng bất kỳ tên nào, ví dụ :slug, :name, vân vân và mây mây- Khi người dùng truy cập
/user/5
, thì id = 5
Bước 3: Thêm link điều hướng
Trong App.vue
:
<template> <div> <nav> <router-link to="/">Trang chủ</router-link> <router-link to="/user/1">User 1</router-link> // Đây là người dùng có ID: 1 <router-link to="/user/2">User 2</router-link> // Đây là người dùng có ID: 2 </nav> <router-view></router-view> </div>
</template>
3. Vuex – Quản lý trạng thái toàn cục
Cài đặt:
npm install vuex
Cấu hình:
import Vue from 'vue';
import Vuex from 'vuex'; Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment(state) { state.count++; } }, actions: { asyncIncrement({ commit }) { setTimeout(() => { commit('increment'); }, 1000); } }, getters: { doubleCount: state => state.count * 2 }
}); new Vue({ el: '#app', store
});
Sử dụng trong component:
<template> <div> <p>Số đếm: {{ count }}</p> <button @click="increment">Tăng</button> </div>
</template> <script>
export default { computed: { count() { return this.$store.state.count; } }, methods: { increment() { this.$store.commit('increment'); } }
}
</script>
📌 Giải thích:
- state: Dữ liệu dùng chung.
- mutations: Cập nhật state (đồng bộ).
- actions: Gọi xử lý bất đồng bộ.
- getters: Tính toán từ state.
4. Giao tiếp component (Component Communication)
4.1 Truyền dữ liệu từ Cha → Con (qua props
)
// ParentComponent.vue <template> <div> <h2>Cha</h2> <ChildComponent :message="parentMessage" /> </div>
</template> <script>
import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, data() { return { parentMessage: "Chào con ta là cha" } }
}
</script>
// ChildComponent.vue: <template> <div> <p>Tin nhắn từ cha: {{ message }}</p> // Result: Tin nhắn từ cha: Chào con ta là cha </div>
</template> <script>
export default { props: ['message']
}
</script>
📌 Giải thích:
:message="parentMessage"
là truyền dữ liệu xuống con- Con nhận dữ liệu qua
props
4.2 Truyền dữ liệu từ Con → Cha (qua $emit)
// ParentComponent.vue: <template> <div> <h2>Cha</h2> <p>Tin nhắn từ con: {{ messageFromChild }}</p> // Result: Tin nhắn từ con: Xin chào tôi là con! <ChildComponent @childMessage="receiveFromChild" /> </div>
</template> <script>
import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, data() { return { messageFromChild: '' } }, methods: { receiveFromChild(data) { this.messageFromChild = data; } }
}
</script>
// ChildComponent.vue <template> <div> <button @click="sendToParent">Gửi dữ liệu cho cha</button> </div>
</template> <script>
export default { methods: { sendToParent() { this.$emit('childMessage', 'Xin chào tôi là con!'); } }
}
</script>
📌 Giải thích:
this.$emit('childMessage', dữ liệu)
dùng để gửi sự kiện kèm dữ liệu lên component cha- Cha nghe bằng
@childMessage="..."
4.3 tiếp giữa các component không liên quan (dùng Event Bus)
Tạo file event-bus.js
// event-bus.js import Vue from 'vue';
export const EventBus = new Vue();
Component A (gửi dữ liệu):
<template> <button @click="sendData">Gửi dữ liệu</button>
</template> <script>
import { EventBus } from './event-bus'; export default { methods: { sendData() { EventBus.$emit('myEvent', 'Dữ liệu từ Component A'); } }
}
</script>
Component B (nhận dữ liệu):
<template> <div> <p>Dữ liệu nhận: {{ received }}</p> </div>
</template> <script>
import { EventBus } from './event-bus'; export default { data() { return { received: '' } }, created() { EventBus.$on('myEvent', (data) => { this.received = data; }); }, beforeDestroy() { EventBus.$off('myEvent'); // tránh memory leak }
}
</script>
📌 Giải thích:
EventBus
là đối tượng trung gian truyền sự kiện giữa cáccomponent
không có quan hệ cha – con.- Dùng
EventBus.$emit()
để gửi,EventBus.$on()
để nhận.
4.4 Truyền dữ liệu từ cháu → ông (nhiều cấp)
Vue 2 không hỗ trợ provide/inject mạnh như Vue 3, nhưng vẫn dùng được: Grandparent.vue
<template> <div> <h2>Ông</h2> <ParentComponent /> </div>
</template> <script>
import ParentComponent from './ParentComponent.vue';
export default { provide() { return { grandpaMessage: "Dữ liệu từ Ông" } }, components: { ParentComponent }
}
</script>
ChildComponent.vue (cháu)
<template> <div> <p>Nhận từ ông: {{ grandpaMessage }}</p> </div>
</template> <script>
export default { inject: ['grandpaMessage']
}
</script>
📌 Giải thích:
provide/inject
giúp chia sẻ dữ liệu qua nhiều cấp component.