Vuejs là một trong những framework JavaScript phổ biến giúp phát triển giao diện web nhanh chóng và hiệu quả. Câu hỏi phỏng vấn Vuejs đi kèm câu trả lời chi tiết sẽ đem đến góc nhìn toàn diện cho bạn, đồng thời giúp bạn có được sự chuẩn bị tốt hơn cho buổi phỏng vấn tiếp theo.
Đọc bài viết sau đây để được giải đáp chi tiết về:
- Câu hỏi phỏng vấn Vuejs mức độ cơ bản.
- Câu hỏi phỏng vấn Vuejs nâng cao dành cho Middle hoặc Senior Developer.
- Câu hỏi phỏng vấn Vuejs xử lý tình huống.
Vuejs là gì?
Vue.js là một framework JavaScript được thiết kế để xây dựng giao diện người dùng và ứng dụng web đơn trang (SPA – Single Page Application). Với cú pháp dễ hiểu, khả năng tái sử dụng component và hệ sinh thái phong phú, Vue.js giúp lập trình viên phát triển ứng dụng nhanh chóng và hiệu quả.
Khác với các framework monolithic thì Vuejs được định hình để lập trình viên có thể áp dụng từng bước. Thư viện cốt lõi chỉ tập trung vào view (view layer) giúp dễ dàng học và tích hợp nhiều thư viện hoặc dự án khác nhau.
Xem thêm: VueJS là gì? Hướng dẫn ứng dụng hiệu quả Vue.js trong lập trình
Hệ sinh thái của Vue.js cũng rất lớn. Bộ công cụ (tooling) và libraries của Vue.js có thể đáp ứng đầy đủ các nhu cầu lập trình cơ bản:
- Vue.js official CLI: Giao diện dòng lệnh được sử dụng để phát triển và cài đặt các thư viện cốt lõi của framework Vue, cũng như các plugin của bên thứ ba. Hiện nay Vite đang được khuyến nghị sử dụng thay thế cho Vue CLI.
- Development Tool (Công cụ phát triển): Các công cụ phát triển trình duyệt được sử dụng để gỡ lỗi trên các ứng dụng được xây dựng bằng Vue.
- Vue Loader: Bộ tải chính thức cho gói web
- Vue Router: Định tuyến và ánh xạ thành phần (mapping component)
- Vuex (hoặc Pinia trong phiên bản mới): Để quản lý state
- Vue Test Utils: Cho unit testing
Ứng dụng của Vuejs trong công việc
Vue.js có thể được sử dụng rộng rãi trong nhiều vị trí công việc khác nhau, bao gồm:
- Front-end Developer: Xây dựng giao diện web động, tối ưu trải nghiệm người dùng.
- Full-stack Developer: Kết hợp Vue.js với các ngôn ngữ lập trình back-end như Node.js, Laravel,… để phát triển ứng dụng hoàn chỉnh.
- UI/UX Developer: Tạo giao diện trực quan, dễ sử dụng với các thư viện Vue UI như Vuetify, Quasar, PrimeVue, Tailwind UI hoặc Element UI.
Bên cạnh việc thành thạo Vue.js, bạn cũng có thể học thêm các kỹ năng khác để nâng cao cơ hội nghề nghiệp của bản thân như:
- JavaScript, CSS và HTML: Hỗ trợ xây dựng trang web.
- Vuex hoặc Pinia: Quản lý state (trạng thái) ứng dụng một cách tối ưu.
- Testing: Kiểm thử ứng dụng Vue.js để đảm bảo chất lượng sản phẩm.
Câu hỏi phỏng vấn Vuejs cho Fresher hoặc Junior Developer
Ứng dụng một trang (Single-Page Application) trong Vuejs là gì?
Ứng dụng một trang (Single-Page Application – SPA) là ứng dụng hoạt động trong một trang web duy nhất, tất cả các trang được tải một lần và nội dung được cập nhật động mà không cần tải lại toàn bộ trang. Khi sử dụng SPA với các tương tác hoặc yêu cầu, nội dung trang của DOM sẽ được cập nhật tự động bằng cách gửi hoặc thực thi các yêu cầu một cách không đồng bộ.
Bạn hiểu gì về Vue Instance? Làm thế nào để tạo được một Vue Instance?
Vue Instance là đối tượng cốt lõi trong Vue.js, đóng vai trò như một ViewModel trong mô hình MVVM, giúp liên kết giữa dữ liệu và giao diện. Vue Instance chịu trách nhiệm tạo và quản lý hệ thống thành phần phân cấp, cũng như xử lý dữ liệu, quản lý trạng thái, sự kiện hay vòng đời (life cycle).
Cách tạo một Vue Instance như sau trong Vue 2:
var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } })
Nhưng cách tạo Vue Instance trong Vue 3 lại có sự khác biệt như sau:
const app = createApp({ data() { return { message: 'Hello Vue!' } } }) app.mount('#app')
Ở ví dụ trên, một Vue Instance được tạo và truyền vào đối tượng tùy chọn theo 2 thuộc tính:
- el: Chỉ định phần tử DOM mà Vue Instance sẽ được gắn vào.
- data: Chỉ định đối tượng dữ liệu chứa trạng thái của ứng dụng.
Sau khi Vue Instance được tạo, nó sẽ quản lý phần tử DOM đã chỉ định và thay thế nội dung của phần tử bằng mẫu và ràng buộc dữ liệu trong Vue Instance.
Component trong Vue.js là gì? Làm thế nào để tạo một component?
Component là một phần tử có thể tái sử dụng trong Vue.js, mô-đun, mẫu, kiểu hay hành vi của một tính năng hoặc thành phần UI cụ thể trong ứng dụng. Một component có thể bao gồm nhiều component khác nhau và giao tiếp với component qua các props hoặc sự kiện.
Để tạo một thành phần trong ‘Vue.js’, bạn có thể sử dụng phương thức ‘Vue.component()’
Vue.component('my-component', { template: '<div>{{ message }}</div>', data: function () { return { message: 'Hello from my component!' } } })
Cú pháp tạo component trong Vue 3 thường dùng Single File Components (.vue)
<template> <div>{{ message }}</div> </template> <script> export default { data() { return { message: 'Hello from my component!' } } } </script>
Ở ví dụ trên, định nghĩa một component có tên là “my-component” và chỉ định các mẫu tùy chọn mẫu cũng như dữ liệu của thành phần đó. Tùy chọn mẫu định nghĩa HTML sẽ được hiển thị khi component được sử dụng và tùy chọn dữ liệu định nghĩa trạng thái ban đầu của dữ liệu component.
Giải thích về mixins trong Vuejs với ví dụ. Ưu và nhược điểm của Mixins?
Trong Vuejs, Mixins là một cách để tái sử dụng mã trong nhiều component khác nhau. Về cơ bản, Mixin là một đối tượng có các tùy chọn component có thể được hợp nhất với các tùy chọn của component khác. Khi một component sử dụng mixin, nó sẽ kế thừa tất cả các thuộc tính và phương thức được xác định trong mixin.
// Định nghĩa mixin với một phương thức chung const greetingMixin = { methods: { greet() { console.log("Hello, world!"); } } }; // Định nghĩa component sử dụng mixin Vue.component("my-component", { mixins: [greetingMixin], template: ` <div> <h1>My Component</h1> <button @click="greet()">Greet</button> </div> ` }); // Tạo một thể hiện Vue với component new Vue({ el: "#app" });
Ở ví dụ trên, tạo một mixin có tên – ‘greetingMixin’ và trong component, bạn có thể sử dụng nó với (mixin : [ ]). Tương tự như vậy, nó có thể được sử dụng ở nhiều component giúp làm giảm khả năng lặp lại của mã.
Mixin có một số ưu điểm nhất định, nhưng bên cạnh đó cũng còn một số nhược điểm. Một số điểm nổi bật cũng như hạn chế của Vuejs bao gồm:
Ưu điểm | Nhược điểm |
Khả năng tái sử dụng mã | Có thể xảy ra xung đột về tên |
Làm giảm sự trùng lặp của mã | Ảnh hưởng đến việc hiểu hành vi của một component khó khăn hơn |
Mã có bố cục rõ ràng và tính mô-đun | Có thể dẫn đến hành vi không mong muốn nếu sử dụng không đúng cách |
Bảo trì và cập nhật mã dễ dàng hơn | Có thể làm tăng độ phức tạp của mã nếu sử dụng quá nhiều mixin |
Được sử dụng để mở rộng và tùy chỉnh chức năng hiện có | Không phải là cách tiếp cận tốt nhất cho mọi trường hợp sử dụng |
Bạn hiểu gì về Virtual DOM trong Vuejs?
Virtual DOM (VDOM) trong Vue.js là một bản sao nhẹ của DOM thật, giúp Vuejs cập nhật giao diện một cách hiệu quả hơn. Khi một component Vue.js được tạo hoặc cập nhật, nó sẽ tạo một biểu diễn DOM ảo về trạng thái hiện tại của nó, sau đó được so sánh với DOM ảo trước đó để xác định tập hợp các thay đổi tối thiểu cần thực hiện đối với DOM thực tế để phản ánh trạng thái đã cập nhật.
VDOM được sử dụng như một kỹ thuật tối ưu hóa để giảm thiểu số lượng thao tác trực tiếp đối với DOM, điều này có thể gây ảnh hưởng về mặt hiệu suất. Thay vì cập nhật DOM thực tế mỗi khi trạng thái của một component thay đổi, Vue.js sử dụng VDOM để tính toán cách hiệu quả nhất để cập nhật DOM và sau đó áp dụng những thay đổi đó theo cách hàng loạt. Điều này có thể dẫn đến cải thiện hiệu suất đáng kể, đặc biệt là trong các ứng dụng lớn và phức tạp.
Giải thích về các vòng đời hook trong Vuejs
Các hook vòng đời (life cycle hook) trong Vue.js là các phương thức đặc biệt được gọi ở nhiều giai đoạn khác nhau trong vòng đời của một thành phần (component). Các hook này cho phép thực thi mã tại các điểm cụ thể trong vòng đời, chẳng hạn như trước khi thành phần được tạo trước khi được gắn kết, sau khi được cập nhật và trước khi bị hủy.
Một số hook phổ biến thường được dùng trong Vuejs có thể kể đến như:
- beforeCreate: Hook này được gọi trước khi thành phần được tạo, giúp khởi tạo dữ liệu và thiết lập trình lắng nghe sự kiện.
- created: Được gọi sau khi thành phần được tạo giúp thực hiện các thiết lập ban đầu như tìm nạp dữ liệu từ API.
- beforeMount: Hook được gọi trước khi thành phần được gắn kết vào DOM giúp thực hiện bất kỳ thao tác DOM cần thiết nào trước khi thành phần được hiển thị.
- mounted: Được gọi sau khi thành phần được gắn kết vào DOM giúp thực hiện bất kỳ thao tác DOM cần thiết nào sau khi thành phần được hiển thị.
- beforeUpdate: Hook được gọi trước khi thành phần được cập nhật do thay đổi trong thuộc tính hoặc trạng thái của thành phần. Hook có hữu ích trong việc thực hiện bất kỳ tác vụ cập nhật trước cần thiết nào.
- updated: Hook được gọi sau khi thành phần được cập nhật do có thay đổi trong props hoặc trạng thái của thành phần đó. Hook này hữu ích để thực hiện bất kỳ tác vụ hậu cập nhật cần thiết nào.
- beforeUnmount: Hook được gọi trước khi thành phần được hủy gắn kết khỏi DOM. Hook có hữu ích để thực hiện bất kỳ tác vụ dọn dẹp cần thiết nào trước khi thành phần được xóa khỏi DOM.
- unmount: Hook được gọi sau khi thành phần được hủy gắn kết khỏi DOM giúp thực hiện bất kỳ tác vụ dọn dẹp cần thiết nào sau khi thành phần được xóa khỏi DOM.
Bằng cách sử dụng các hook này trong các thành phần Vue.js, bạn có thể thực thi mã tại các điểm cụ thể trong vòng đời của thành phần. Bên cạnh đó, chúng cũng cho phép bạn thực hiện các quá trình khởi tạo, dọn dẹp hay các tác vụ khác khi cần thiết.
Hooks trong Vuejs là gì? Liệt kê các hooks Vuejs phổ biến
Hook là tính năng mới được giới thiệu trong Vue.js 3, cho phép thêm logic và quản lý trạng thái vào các thành phần một cách có tổ chức và có thể tái sử dụng. Hook tương tự như hook vòng đời (life cycle hook), nhưng cho phép đóng gói và tái sử dụng trên nhiều thành phần.
Vue.js cung cấp một số hook tích hợp có thể sử dụng để thêm chức năng vào các thành phần. Một số hook được sử dụng phổ biến nhất bao gồm:
- ‘setup’: Đây là hook chính được sử dụng để thêm logic và quản lý trạng thái vào thành phần. Hàm setup được gọi trước khi thành phần được tạo và cho phép định nghĩa dữ liệu phản ứng, phương thức, thuộc tính được tính toán hay logic khác có thể được truy cập bởi template của thành phần.
- ‘onMounted’: Hook này được gọi sau khi thành phần được gắn vào DOM, có thể sử dụng để thực hiện bất kỳ thao tác DOM hoặc hoạt động truy xuất dữ liệu cần thiết nào.
- ‘onUpdated’: Hook này được gọi sau khi thành phần được cập nhật do thay đổi trong thuộc tính hoặc trạng thái của thành phần. Hook có thể sử dụng để thực hiện bất kỳ tác vụ nào cần thiết sau khi cập nhật.
- ‘onUnmounted’: Được gọi trước khi thành phần được gỡ khỏi DOM. Hook có thể được sử dụng để thực hiện bất kỳ tác vụ dọn dẹp cần thiết nào trước khi thành phần được xóa khỏi DOM.
Liên kết dữ liệu (data binding) trong Vuejs là gì? Có bao nhiêu loại liên kết dữ liệu trong Vuejs?
Liên kết dữ liệu (data binding) là quá trình đồng bộ hóa dữ liệu giữa Vuejs và DOM. Chúng cho phép bạn thiết lập kết nối giữa dữ liệu và UI, để bất kỳ thay đổi nào đối với dữ liệu đều được phản ánh tự động trong UI và bất kỳ thay đổi nào đối với UI đều được phản ánh tự động trong dữ liệu.
Có ba loại liên kết dữ liệu trong Vue.js:
- Interpolation: Đây là liên kết một chiều cho phép nhúng giá trị của thuộc tính dữ liệu vào nội dung của phần tử HTML. Nó được biểu thị bằng dấu ngoặc nhọn kép ‘{{ }}’.
- Liên kết thuộc tính (Property binding): Đây là liên kết một chiều cho phép đặt giá trị của thuộc tính của phần tử HTML thành giá trị của thuộc tính dữ liệu. Nó được biểu thị bằng chỉ thị ‘v-bind’.
- Liên kết hai chiều (Two-way binding): Điều này cho phép liên kết giá trị của một phần tử đầu vào biểu mẫu với một thuộc tính dữ liệu, để các thay đổi đối với các phần tử đầu vào được phản ánh trong dữ liệu và ngược lại. Nó được biểu thị bằng chỉ thị ‘v-model’.
Làm thế nào để truyền dữ liệu giữa các component trong Vuejs?
Bạn có thể thực hiện quá trình truyền dữ liệu giữa các thành phần bằng cách sử dụng Props, event bus hoặc Vuex store. Cụ thể như sau:
Props: Giống như một đối số được đưa cho thành phần. Thuật ngữ được sử dụng để định nghĩa điều này là một thuộc tính. Thuộc tính này được đăng ký trên thành phần và cho phép truyền dữ liệu từ thành phần cha sang thành phần con. Để truyền dữ liệu qua props, bạn có thể định nghĩa prop trên thành phần con, sau đó liên kết dữ liệu với prop trên thành phần cha.
<!-- Thành phần cha--> <template> <child-component :message="parentMessage"></child-component> </template> <!-- Thành phần con --> <script> export default { props: { message: String } } </script>
Hoặc bạn có thể thực hiện truyền dữ liệu bằng cách sử dụng event bus. Đó là một Vue Instance mà bạn có thể sử dụng để phát và lắng nghe các sự kiện trên nhiều thành phần khác nhau. Để truyền dữ liệu bằng event bus, bạn có thể chỉ cần phát một sự kiện với dữ liệu từ một thành phần, sau đó lắng nghe sự kiện và nhận dữ liệu trong một thành phần khác.
export const bus = new Vue() // Phát ra một sự kiện có dữ liệu trong Component A bus.$emit('my-event', data) // Nghe sự kiện và nhận dữ liệu ở Component B bus.$on('my-event', data => { })
Cuối cùng, bạn có thể sử dụng Vuex store. Đây là một mẫu quản lý trạng thái và thư viện cho các ứng dụng Vue.js. Nó cho phép định nghĩa một kho lưu trữ tập trung để quản lý trạng thái của ứng dụng và cung cấp một cách để truy cập hay thay đổi trạng thái từ các thành phần khác nhau.
Để truyền dữ liệu bằng Vuex store, bạn có thể chỉ cần định nghĩa một thuộc tính trạng thái và phương thức thay đổi trong kho lưu trữ, sau đó phân phối thay đổi với dữ liệu từ một thành phần, rồi truy cập thuộc tính trạng thái trong một thành phần khác.
// Lưu trữ trường hợp với thuộc tính trạng thái và đột biến export const store = new Vuex.Store({ state: { message: '' }, mutations: { setMessage (state, payload) { state.message = payload } } }) // Phân phối đột biến với dữ liệu trong Component A store.commit('setMessage', data) // Truy cập thuộc tính trạng thái trong Component B this.message = this.$store.state.message
Giải thích sự khác nhau giữa liên kết dữ liệu một chiều (one-way data flow) và liên kết dữ liệu hai chiều (two-way data binding) trong Vuejs
Một số điểm khác biệt giữa liên kết dữ liệu một chiều (one-way data binding) và liên kết dữ liệu hai chiều (two-way data binding) trong Vuejs như sau:
Tiêu chí | One-way data binding | Two-way data binding |
Định nghĩa | Dữ liệu chỉ đi từ component cha đến con, không thể thay đổi trực tiếp từ component con. | Dữ liệu có thể truyền từ cả hai phía component cha đến component con. |
Cú pháp | Dữ liệu được truyền từ thành phần cha sang thành phần con thông qua props. | Dữ liệu được liên kết với các thành phần đầu vào thông qua ‘v-model’. |
Ví dụ | <child-component :message=”parentMessage”></child-component> | <input v-model=”message”> |
Lợi ích | Dữ liệu đơn giản, dễ theo dõi khi dữ liệu thay đổi.
Hiệu suất được cải thiện do luồng dữ liệu một chiều |
Dễ xử lý dữ liệu đầu vào của người dùng và dữ liệu biểu mẫu.
Giảm lượng mã cần thiết để xử lý đồng bộ hóa dữ liệu. |
Hạn chế | Phức tạp hơn khi triển khai luồng dữ liệu hai chiều.
Có thể khiến việc theo dõi các thay đổi dữ liệu trở nên khó khăn hơn. |
Có thể khiến việc theo dõi thay đổi dữ liệu trở nên khó khăn hơn.
Luồng dữ liệu phức tạp hơn có thể làm giảm hiệu suất. |
Câu hỏi phỏng vấn Vuejs cho Middle Developer
Sự khác nhau giữa hook mounted và created trong Vuejs
Trong suốt vòng đời, các thành phần trải qua nhiều giai đoạn, trong đó hook created và mounted đều hoạt động như các công cụ để thực hiện các hành động có liên quan. Mặc dù có một số khác biệt giữa chúng.
Khi một thành phần được tạo, hook “created” được gọi ngay lập tức và cung cấp quyền truy cập vào dữ liệu của thành phần để điều chỉnh. Hook created có thể được sử dụng cho các tác vụ tổ chức như cấu hình phương thức, dữ liệu và sự kiện cần thiết cho chức năng chung của thành phần
Ngay sau khi template của thành phần được biên dịch, rendered và chèn vào DOM, hook mounted sẽ hoạt động. Hook này rất cần thiết để thực hiện bất kỳ tác vụ nào yêu cầu sử dụng DOM. Điều này có thể liên quan đến việc thiết lập trình lắng nghe sự kiện hoặc khởi động các thư viện của bên thứ ba.
Bạn hiểu gì về watcher trong Vuejs? Khi nào nên sử dụng chúng?
Trong Vue.js, watcher là một đối tượng đặc biệt cho phép theo dõi các thay đổi trong một thuộc tính dữ liệu cụ thể và thực hiện một số hành động khi thuộc tính đó thay đổi. Watcher là một phần quan trọng của hệ thống phản ứng (reactivity system) của Vue.js, sẽ tự động kích hoạt sự kiện và cập nhật chế độ xem khi dữ liệu thay đổi.
Watcher đặc biệt hữu ích khi cần thực hiện một số hành động để phản hồi các thay đổi trong dữ liệu mà không thể thực hiện được bằng các thuộc tính hoặc phương thức được tính toán.
Ví dụ: Bạn có thể sử dụng watcher để cập nhật biểu đồ hoặc đồ thị để phản hồi các thay đổi trong nguồn dữ liệu. Hoặc có thể kích hoạt lệnh gọi API khi một thuộc tính dữ liệu cụ thể thay đổi.
// Basic watcher watch: { value(newVal, oldVal) {} } // Deep watcher watch: { obj: { deep: true, handler(newVal) {} } } // Immediate watcher watch: { value: { immediate: true, handler(newVal) {} } }
Bạn sẽ xử lý xác thực (authentication) và ủy quyền (authorization) trong ứng dụng Vue.js như thế nào?
Xác thực (authentication) và ủy quyền (authorization) là những khía cạnh quan trọng của phát triển ứng dụng web và Vue.js cung cấp một số phương pháp để xử lý chúng. Một số phương pháp thường được sử dụng là:
- Xác thực: Để xử lý xác thực trong ứng dụng Vue.js, có thể sử dụng thư viện xác thực (an authentication library) như JWT hoặc OAuth2.0. Sau khi đăng nhập, thư viện xác thực sẽ tạo mã thông báo mà bạn có thể lưu trữ trong bộ nhớ cục bộ hoặc cookie của trình duyệt. Sau đó, đưa mã thông báo này vào tất cả các yêu cầu tiếp theo tới máy chủ để xác minh danh tính của người dùng.
Ví dụ: Bạn có thể sử dụng thư viện vue-authenticate để triển khai xác thực OAuth2.0 trong ứng dụng Vue.js. Sau khi người dùng đăng nhập bằng thông tin đăng nhập của họ, thư viện sẽ truy xuất mã thông báo truy cập mà bạn có thể sử dụng để xác thực các yêu cầu tiếp theo.
- Ủy quyền: Để xử lý ủy quyền trong ứng dụng Vue.js, có thể triển khai kiểm soát truy cập dựa trên vai trò (RBAC) hoặc kiểm soát truy cập dựa trên thuộc tính (ABAC). Với RBAC, bạn có thể xác định các vai trò tương ứng với các cấp độ truy cập khác nhau và chúng ta chỉ định các vai trò này cho người dùng. Với ABAC, bạn có thể định nghĩa các chính sách chỉ định người dùng nào được phép thực hiện các hành động cụ thể.
Ví dụ: Bạn có thể sử dụng thư viện vue-acl để triển khai RBAC trong ứng dụng Vue.js. Thư viện này cung cấp một phần mềm trung gian có thể sử dụng để hạn chế quyền truy cập vào các tuyến đường hoặc thành phần cụ thể dựa trên vai trò của người dùng.
Làm thế nào để xử lý lỗi trong Vuejs? Giải thích kèm ví dụ.
Có một số cách xử lý lỗi trong Vue.js tùy thuộc vào ngữ cảnh và loại lỗi. Sau đây là một số cách tiếp cận phổ biến:
Cách 1: Xử lý lỗi trong các thành phần (Error handling in Component)
Để xử lý lỗi trong các component, bạn có thể sử dụng khối try-catch. Nếu lỗi xảy ra trong thành phần, khối catch sẽ bắt lỗi và bạn có thể thực hiện hành động thích hợp để xử lý lỗi.
Ví dụ: Bạn có thể hiển thị thông báo lỗi cho người dùng, ghi lại lỗi hoặc thậm chí gửi đến máy chủ để phân tích thêm.
<template> <div> <button @click="handleClick">Click Me</button> </div> </template> <script> export default { methods: { handleClick() { try { // Mã có thể bị lỗi } catch (error) { // Khắc phục lỗi } } } } </script>
Cách 2: Xử lý lỗi toàn cục (global errors)
Để xử lý lỗi toàn cục, bạn có thể sử dụng thuộc tính errorHandler của đối tượng cấu hình. Điều này cho phép bắt và xử lý lỗi xảy ra ở bất kỳ đâu trong ứng dụng của bạn. Hãy xem ví dụ bên dưới để hiểu rõ hơn.
import Vue from 'vue' Vue.config.errorHandler = function (error, vm, info) { // Khắc phục lỗi }
Cách 3: Xử lý lỗi trong Promis (Promise errors)
Để sử dụng Promise trong ứng dụng Vue.js, bạn có thể sử dụng phương thức catch để xử lý lỗi xảy ra trong quá trình hoạt động không đồng bộ. Cụ thể như sau:
this.$http.get('/api/data') .then(response => { // Xử lý phản hồi }) .catch(error => { // Xử lý lỗi })
Sự khác nhau giữa Vuejs, React và Angular?
Dưới đây là bảng so sánh một số điểm khác biệt giữa Vuejs, React và Angular:
Tiêu chí | Vuejs | React | Angular |
Ngôn ngữ | JavaScript/TypeScript (Vue 3 được viết bằng TypeScript và hỗ trợ tốt TypeScript) | JavaScript/TypeScript | TypeScript |
Template | Single File Components (.vue). Template syntax với HTML-based DSL và hỗ trợ JSX/TSX | Sử dụng JSX, cho phép viết mã HTML bên trong javascript. Cũng hỗ trợ template literals | Sử dụng template dựa trên HTML. Có template syntax riêng |
Size | Framework nhỏ và gọn. Kích thước ~33KB (chỉ runtime). | Framework nhỏ và gọn. Kích thước nhỏ ~42KB (react + react-dom). | Framework lớn hơn, với kích thước ~150KB (các core packages). |
Rendering | Chủ yếu là một khung kết xuất phía máy khách, nghĩa là kết xuất toàn bộ ứng dụng ở phía máy khách bằng JavaScript. Vue.js cũng có thể được sử dụng để kết xuất phía máy chủ và có hỗ trợ Static site generation | Chủ yếu là một khung kết xuất phía máy khách. Server-side rendering với Next.js và Static site generation | Được thiết kế kết xuất cả phía máy khách và phía máy chủ. Sử dụng cú pháp đặc biệt có tên là Angular Universal để cho phép bạn kết xuất ứng dụng của mình ở phía máy chủ. |
State | Có một thư viện quản lý trạng thái chính thức tên là Vuex, cung cấp cách quản lý trạng thái theo cách tập trung và có thể dự đoán được. Cũng có thể sử dụng Pinia (được khuyến nghị cho Vue 3) | Có một thư viện quản lý trạng thái không chính thức là Redux, đã trở nên rất phổ biến trong cộng đồng React. React cũng có một hook tích hợp (useState) có thể được sử dụng để quản lý trạng thái.
Ngoài ra có thể sử dụng MobX, Recoil, Context API + useState/useReducer |
Có khả năng quản lý trạng thái tích hợp và sử dụng kết hợp các dịch vụ, observable và thư viện RxJS để quản lý trạng thái. Ngoài ra có thể sử dụng NgRx (Redux pattern), Signals (mới trong Angular 16+) |
Đọc thêm: So sánh Angular và ReactJS: Framework Frontend nào tốt hơn?
Bạn sẽ triển khai lazy-loading trong ứng dụng Vue.js như thế nào?
Lazy loading về cơ bản là chia nhỏ mã và bạn có thể thực hiện thủ thuật thú vị này với Webpack. Đây chỉ là một cách tuyệt vời để đóng gói cho các dự án Vue CLI. Sau đây là các bước chung để triển khai lazy-loading trong ứng dụng Vue.js:
- Cấu hình webpack: Trong tệp vue.config.js của dự án, bạn cần thiết lập webpack để nó cắt ứng dụng thành các phần nhỏ hơn bằng cách sử dụng splitChunks hoặc dynamicImport.
- Xác định một đoạn dựa trên route: Trong bộ định tuyến Vue, có thể xác định một số đoạn mã cho một tuyến đường cụ thể bằng cách sử dụng thuộc tính thành phần và một hàm. Điều này sẽ trả về một câu lệnh import động cho thành phần.
- Sử dụng thành phần lazy-loaded: Trong các mẫu Vue của bạn, hãy sử dụng phần tử thành phần và liên kết thuộc tính với tên thành phần lazy-loaded.
Ví dụ:
<!-- Template --> <template> <div> <!-- Sử dụng v-lazy directive để lazy load hình ảnh --> <img v-lazy="imageSrc" alt="Image"> </div> </template> <script> import Vue from 'vue'; import VueLazyload from 'vue-lazyload'; export default { data() { return { imageSrc: 'path/to/image.jpg' } }, mounted() { Vue.use(VueLazyload, { preLoad: 1.3, error: 'path/to/error.png', loading: 'path/to/loading.gif', attempt: 1 }); } } </script>
Bạn sẽ tích hợp thư viện của bên thứ ba (third-party) vào ứng dụng Vue.js như thế nào?
Để tích hợp thư viện của bên thứ ba vào ứng dụng Vue.js, có thể làm theo các bước chung sau:
- Cài đặt thư viện: Sử dụng trình quản lý gói như npm hoặc yarn để cài đặt thư viện dưới dạng phụ thuộc.
- Nhập (import) thư viện: Nhập thư viện vào điểm vào của ứng dụng Vue.js (ví dụ: main.js) bằng cú pháp phù hợp cho thư viện. Điều này có thể bao gồm nhập thư viện dưới dạng mô-đun, tải tệp tập lệnh từ CDN hoặc sử dụng plugin đặc biệt cho thư viện.
- Sử dụng thư viện trong các thành phần: Tùy thuộc vào thư viện, bạn có thể cần định cấu hình hoặc khởi tạo thư viện trước khi có thể bắt đầu sử dụng thư viện trong các thành phần Vue.js của mình. Sau đó, sử dụng API và hàm của thư viện trong các phương thức thành phần, thuộc tính được tính toán hoặc móc vòng đời.
Ví dụ:
// Global registration import ThirdPartyLib from 'third-party-lib' app.use(ThirdPartyLib) // Plugin creation const myPlugin = { install(app, options) { // Plugin logic } } // Component-level integration import { someFeature } from 'third-party-lib' export default { mounted() { someFeature.init(this.$el) } }
Sự khác nhau giữa thành phần chức năng (functional component) và thành phần thông thường (regular component) trong Vuejs?
Tiêu chí | Thành phần chức năng | Thành phần thông thường |
Loại (type) | Stateless và đơn giản, chỉ nhận props và trả về JSX | Stateful và phức tạp, có thể chứa logic và dữ liệu bên trong |
Life cycle hook | Không có lifecycle hooks (do stateless) | Đầy đủ các lifecycle hooks như created, mounted, updated, destroyed |
Render | Sử dụng hàm render duy nhất, tối ưu cho hiệu suất | Được định nghĩa bằng mẫu hoặc hàm render. |
Dữ liệu | Không có dữ liệu hoặc phương thức. Dữ liệu được truyền qua props | Có thể có dữ liệu hoặc phương thức |
Hiệu suất | Hiệu suất tốt với chi phí thấp | Chi phí hiệu suất thấp |
Communication | Phải sử dụng props và phát ra sự kiện. | Có thể sử dụng props, event và và có thể truy cập trực tiếp vào các phương thức của component con (qua ref) |
Ví dụ tạo một functional component như sau:
// Sử dụng `functional` option Vue.component('my-functional-component', { functional: true, render: function (createElement, context) { // Kết xuất logic function ở đây } }) // Sử dụng cú pháp viết tắt export default { functional: true, render: (h, context) => { // Kết xuất logic function ở đây } }
Một ví dụ về việc sử dụng regular component như sau:
Vue.component('my-regular-component', { template: ` <div> <!-- Template markup here --> </div> `, data() { return { } }, methods: { }, }) // Sử dụng render function Vue.component('my-regular-component', { render: function (createElement) { }, data() { return { } }, methods: { }, })
Sự khác nhau giữa thành phần đồng bộ (synchronous component) và thành phần không đồng bộ (asynchronous components) trong Vue.js?
Tiêu chí | Thành phần đồng bộ | Thành phần không đồng bộ |
Thời gian tải (loading time) | Được tải trong quá trình tạo ứng dụng | Chỉ tải khi cần thiết |
Câu lệnh nhập | Trong file chính | Trong thành phần cha |
Kích thước | Tăng kích thước bundle ban đầu | Giảm kích thước bundle ban đầu |
Hiệu suất | Có thể tác động đến thời gian tải ban đầu và hiệu suất của ứng dụng. | Cải thiện thời gian tải ban đầu và hiệu suất của ứng dụng. |
Định nghĩa | Được định nghĩa đồng bộ trong thành phần cha. | Được định nghĩa không đồng bộ bằng cách sử dụng factory component và dynamic import. |
Ứng dụng template | Có thể sử dụng trực tiếp trong các template | Phải được bao bọc trong thẻ <component> với thuộc tính is hoặc sử dụng dynamic component |
Thành phần động | Không phù hợp kết xuất | Phù hợp để kết xuất |
Phân tách mã | Không thể phân chia mã | Có thể phân chia mã |
Kết xuất phía máy chủ trong Vue.js là gì và nó khác với kết xuất phía máy khách như thế nào?
Kết xuất phía máy chủ (SSR) là một thủ thuật phát triển web liên quan đến việc tạo nội dung HTML trên máy chủ và chuyển đến máy khách dưới dạng trang HTML hoàn chỉnh. Vue.js sao lưu SSR và có thể được sử dụng cùng với kết xuất phía máy khách để tạo ra các ứng dụng đa năng.
Trong quá trình kết xuất ở phía máy khách, trình duyệt sẽ lấy các mã và thiết kế trang web cơ bản để khởi chạy chế độ xem trang ở phía người dùng. Khi người dùng chỉnh sửa trang, phía người dùng xử lý sẽ tiếp cận để lấy dữ liệu mới từ máy chủ và điều chỉnh các thẻ HTML cốt lõi theo yêu cầu. Cách này có những ưu điểm
- Mở rộng trang trong một dấu gạch ngang, thực hiện một số thay đổi tương tác tuyệt vời và giúp công việc của người viết mã dễ dàng hơn rất nhiều.
- Tuy nhiên, nó cũng có nhược điểm như khi nói đến SEO, sẽ có một số vấn đề và thời gian đưa nội dung của trang sẽ kéo dài một chút.
Mặt khác, SSR thực hiện hướng nội dung HTML ở phía máy chủ và gửi đến máy khách dưới dạng trang HTML đầy đủ. Cách này sẽ mất nhiều thời gian hơn để trang hiển thị lần đầu tiên, nhưng khi đã hiển thị, nó đã hoạt động hoàn hảo. Bên cạnh đó, SSR có một số ưu điểm so với kết xuất phía máy khách như tối ưu hóa công cụ tìm kiếm tốt hơn, thời gian tải nội dung nhanh hơn và hiệu suất ổn định hơn trên các thiết bị yếu.
Để xem SSR trong Vue.js, bạn phải sử dụng máy chủ dựa trên Node.js để đưa ra nội dung HTML đầu tiên. Khi người dùng yêu cầu một trang, mã ở phía máy chủ sẽ tạo nội dung HTML bằng các tiện ích của Vue.js và gửi đến trình phát. Khi trang đã sẵn sàng, mã phía máy khách sẽ lấy các đoạn mã và cập nhật DOM khi cần.
Câu hỏi phỏng vấn Vuejs xử lý tình huống thực tế
Bạn sẽ tối ưu hóa hiệu suất của một ứng dụng Vue.js lớn như thế nào?
Tối ưu hóa hiệu suất của một ứng dụng Vue.js lớn đòi hỏi một số giải pháp giải quyết các lĩnh vực khác nhau của ứng dụng. Bạn có thể tham khảo và trình bày một số chiến lược phổ biến như:
- Lazy loading: Thay vì tải mọi thứ cùng một lúc thì có thể chia ứng dụng thành các phần nhỏ hơn và tải chúng theo yêu cầu bằng cách sử dụng tải chậm. Phương pháp chia nhỏ này có thể giảm đáng kể thời gian tải ban đầu và nâng cao hiệu suất chung của ứng dụng.
- Chia mã (code splitting): Có thể chia mã thành các phần nhỏ hơn, và chỉ có thể tải thành phần cần thiết. Sử dụng phương pháp này giúp giảm kích thước của ứng dụng và có thể cải thiện hiệu suất của ứng dụng.
- Thu nhỏ và nén: Có thể nén kích thước ứng dụng và sử dụng phiên bản thu nhỏ của các tệp Javascript và CSS (như jquery.min-js). Điều này giúp tăng tốc độ tải xuống và tăng hiệu suất.
- Lưu trữ đệm: C\ó thể lưu trữ đệm các thứ như ảnh, phông chữ và phản hồi API để không gây quá nhiều tải cho mạng và giúp ứng dụng chạy nhanh hơn.
- Sử dụng Vuex để quản lý trạng thái: Vue.js cung cấp Vuex (một thư viện quản lý trạng thái). Điều này cho phép quản lý trạng thái của ứng dụng trong một kho lưu trữ tập trung. Sử dụng Vuex có thể giúp cắt giảm số lượng lệnh gọi API và làm cho ứng dụng Vue.js hoạt động nhanh hơn.
- Sử dụng Async Components: Cho phép tải các thành phần theo yêu cầu, có thể giúp giảm các lệnh gọi/yêu cầu không cần thiết của các thành phần tại thời điểm ban đầu.
- Tối ưu hóa các chỉ thị Vue.js: Sử dụng v-if thay vì v-show để hiển thị các thành phần có điều kiện. Ngoài ra, có thể sử dụng v-for với thuộc tính key và sử dụng v-cloak để ẩn các mẫu Vue.js chưa biên dịch.
- Server-side Rendering: Giúp tải trước một số tệp HTML, CSS và JavaScript cần thiết. Điều này có thể cải thiện hiệu suất về mặt SEO.
- Sử dụng các công cụ phân tích hiệu suất: Có nhiều công cụ phân tích hiệu suất khác nhau có thể sử dụng như: Google Chrome Developer Tools, Vue.js Developer Tools,… Điều này giúp gỡ lỗi độ phức tạp để có thể giảm thiểu và tối ưu hóa hiệu suất.
- Sử dụng v-if thay cho v-show khi điều kiện ít thay đổi: v-if sẽ không render element nếu điều kiện là false, giúp giảm tải cho DOM.
Nếu một component Vue.js không cập nhật khi dữ liệu thay đổi, bạn sẽ kiểm tra điều gì?
Khi component bị lỗi không cập nhật dữ liệu, đầu tiên bạn cần chắc chắn kiểm tra về các lỗi cơ bản như lỗi đánh máy, cập nhật đúng component, đúng trang hoặc không vô tình tạo một array mới bằng một object.
Sau khi đã kiểm tra các lỗi cơ bản nhưng component vẫn không cập nhật dữ liệu thì bạn có thể xét tiếp đến các một số lỗi như:
- Kiểm tra các biến có phản ứng không, có thể do bạn cập nhật biến ở một component khác, sử dụng biến trong computed prop không cập nhật, hay cập nhật Vuex nhưng component không cập nhật.
- Đảm bảo cập nhật array và object một cách chính xác (đối với Vue2).
- Sử dụng props trực tiếp nếu bạn thay đổi props nhưng dữ liệu vẫn chưa cập nhật.
- Sử dụng computed props với Vuex, có thể xảy ra trong trường hợp giá trị của Vuex bị thay đổi.
- Chắc chắn rằng bạn không làm thay đổi props hoặc Vuex state, điều này có thể xảy ra khi bạn cập nhật giá trị của props hoặc Vuex state.
Làm thế nào để bảo mật dữ liệu khi sử dụng Vue.js?
Bảo mật là một yếu tố quan trọng khi phát triển ứng dụng Vue.js, đặc biệt khi ứng dụng xử lý dữ liệu nhạy cảm như thông tin người dùng, thanh toán, hoặc dữ liệu doanh nghiệp. Một số biện pháp giúp bảo vệ dữ liệu khi sử dụng Vuejs có thể kể đến như:
- Không lưu thông tin nhạy cảm trên client-side, không nên được lưu trữ trong localStorage hoặc sessionStorage. Thay vào đó, hãy lưu trữ token trên cookies có HttpOnly (được gửi từ server và không thể bị truy cập bởi JavaScript).
- Sử dụng HTTPS để mã hóa dữ liệu.
- Tránh XSS (Cross-Site Scripting) bằng cách sanitize input.
- Bảo vệ API và dữ liệu backend.
Làm thế nào để xác định lỗi và debug một ứng dụng Vue.js kích thước lớn?
Debugging trong Vue.js là một phần quan trọng giúp phát hiện và khắc phục lỗi trong ứng dụng, đặc biệt khi dự án ngày càng lớn. Để xác định lỗi và debug, có thể áp dụng một số cách như:
Sử dụng Vue Devtool để theo dõi trạng thái và lỗi
Vue DevTools là công cụ chính thức của Vue giúp kiểm tra trạng thái của component, dữ liệu reactive, Vuex/Pinia store, route, event,…
Cách cài đặt: Nếu dùng Chrome hoặc Firefox, bạn có thể cài đặt Vue DevTools từ Chrome Web Store hoặc Firefox Add-ons.
Cách sử dụng:
- Kiểm tra component tree để theo dõi dữ liệu state và props.
- Debug Vuex/Pinia để xem lịch sử thay đổi trạng thái.
- Xem console logs để phát hiện lỗi liên quan đến lifecycle hooks hoặc dữ liệu bị thay đổi không mong muốn.
Sử dụng console.log(), debugger và breakpoints
- console.log(): Dùng để kiểm tra giá trị biến, dữ liệu props và state trong từng bước xử lý logic.
- debugger: Chèn vào code để tạm dừng thực thi, giúp kiểm tra biến trực tiếp trong trình duyệt DevTools.
Làm thế nào để bảo vệ route yêu cầu đăng nhập trong Vue Router?
Khi phát triển một ứng dụng Vue.js có các trang chỉ dành cho người dùng đã đăng nhập (như trang dashboard, quản lý tài khoản), bạn cần thiết lập bảo vệ route để ngăn chặn truy cập trái phép. Điều này có thể được thực hiện bằng cách sử dụng Navigation Guards của Vue Router để kiểm tra trạng thái đăng nhập trước khi cho phép người dùng truy cập vào một route cụ thể.
Navigation Guards cung cấp các hook như beforeEach(), giúp bạn có thể kiểm tra điều kiện trước khi người dùng điều hướng đến một trang mới.
Ví dụ: Kiểm tra trạng thái đăng nhập trước khi truy cập các route yêu cầu quyền truy cập.
import { createRouter, createWebHistory } from 'vue-router'; import store from '@/store'; import Login from '@/views/Login.vue'; import Dashboard from '@/views/Dashboard.vue'; const routes = [ { path: '/login', component: Login }, { path: '/dashboard', component: Dashboard, meta: { requiresAuth: true } // Đánh dấu route yêu cầu đăng nhập } ]; const router = createRouter({ history: createWebHistory(), routes }); // Kiểm tra quyền truy cập trước khi vào trang yêu cầu đăng nhập router.beforeEach((to, from, next) => { const isAuthenticated = store.state.isAuthenticated; // Kiểm tra trạng thái đăng nhập từ Vuex/Pinia hoặc localStorage if (to.meta.requiresAuth && !isAuthenticated) { next('/login'); // Chuyển hướng về trang đăng nhập nếu chưa đăng nhập } else { next(); // Tiếp tục điều hướng nếu hợp lệ } }); export default router;
Tổng kết câu hỏi phỏng vấn VueJS
Bộ 30+ câu hỏi phỏng vấn VueJS trên không chỉ kiểm tra kiến thức về cơ bản mà còn đánh giá tư duy phát triển ứng dụng của bạn. Việc nắm vững các khái niệm quan trọng và thực hành thường xuyên sẽ giúp bạn dễ dàng vượt qua phỏng vấn cũng như cơ hội mở rộng cơ hội nghề nghiệp tốt hơn.