Trong thế giới phát triển web hiện nay, việc quản lý điều hướng trở nên ngày càng quan trọng. Trang web Cafedev hôm nay muốn chia sẻ với bạn về cách sử dụng các bộ lọc điều hướng trong Vue Router. Với các bộ lọc này, bạn có thể kiểm soát việc điều hướng của ứng dụng VueJS của mình một cách linh hoạt và mạnh mẽ. Hãy cùng khám phá những điều thú vị về Router VueJS với các bộ lọc điều hướng!
Như tên gọi, các bộ lọc điều hướng được cung cấp bởi Vue Router chủ yếu được sử dụng để bảo vệ các điều hướng bằng cách chuyển hướng hoặc hủy bỏ nó. Có một số cách để kết nối vào quá trình điều hướng địa chỉ: toàn cầu, theo từng địa chỉ, hoặc trong các thành phần.
Nội dung chính
1. Các Bộ Lọc Toàn Cầu Trước
Bạn có thể đăng ký các bộ lọc toàn cầu trước bằng cách sử dụng router.beforeEach
:
const router = createRouter({ ... })
router.beforeEach((to, from) => {
// ...
// explicitly return false to cancel the navigation
return false
})
Các bộ lọc toàn cầu trước được gọi theo thứ tự tạo, mỗi khi một cuộc điều hướng được kích hoạt. Các bộ lọc có thể được giải quyết bất đồng bộ, và cuộc điều hướng được coi là đang chờ cho đến khi tất cả các khớp đã được giải quyết.
Mỗi hàm bộ lọc nhận hai đối số:
to
: địa chỉ địa điểm đích trong định dạng chuẩn hóa đang được điều hướng tới.from
: địa chỉ địa điểm hiện tại trong định dạng chuẩn hóa đang được rời đi.
Và có thể trả về tùy chọn sau:false
: hủy bỏ điều hướng hiện tại. Nếu URL của trình duyệt được thay đổi (hoặc bằng cách thủ công bởi người dùng hoặc thông qua nút back), nó sẽ được đặt lại thành của địa chỉfrom
.- Một Địa điểm Địa chỉ: Chuyển hướng đến một vị trí khác bằng cách truyền một vị trí địa chỉ như bạn đang gọi
router.push()
, cho phép bạn truyền các tùy chọn nhưreplace: true
hoặcname: 'home'
. Cuộc điều hướng hiện tại sẽ bị loại bỏ và một cuộc điều hướng mới được tạo với cùngfrom
.
router.beforeEach(async (to, from) => {
if (
// make sure the user is authenticated
!isAuthenticated &&
// ❗️ Avoid an infinite redirect
to.name !== 'Login'
) {
// redirect the user to the login page
return { name: 'Login' }
}
})
Cũng có thể ném một
Lỗi
nếu gặp tình huống không mong muốn. Điều này cũng sẽ hủy bỏ điều hướng và gọi bất kỳ hồi đáp nào đã được đăng ký qua router.onError().
Nếu không có gì,undefined
hoặctrue
được trả về, điều hướng được xác nhận, và bộ lọc điều hướng kế tiếp được gọi.
Tất cả các điều trên hoạt động giống nhau với các hàm async
và Promises:
router.beforeEach(async (to, from) => {
// canUserAccess() returns `true` or `false`
const canAccess = await canUserAccess(to)
if (!canAccess) return '/login'
})
Tham số thứ ba tùy chọn next
Trong các phiên bản trước của Vue Router, cũng có thể sử dụng một tham số thứ ba next
, điều này là một nguồn lỗi phổ biến và đã được đi qua một RFC để loại bỏ nó. Tuy nhiên, nó vẫn được hỗ trợ, có nghĩa là bạn có thể truyền một tham số thứ ba vào bất kỳ bộ lọc điều hướng nào. Trong trường hợp đó, bạn phải gọi next
chính xác một lần trong mọi lần đi qua một bộ lọc điều hướng. Nó có thể xuất hiện nhiều lần, nhưng chỉ nếu các đường dẫn logic không chồng chéo, nếu không, hook sẽ không bao giờ được giải quyết hoặc tạo ra lỗi. Dưới đây là một ví dụ xấu về chuyển hướng người dùng đến /login
nếu họ chưa được xác thực:
// BAD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
// if the user is not authenticated, `next` is called twice
next()
})
Đây là phiên bản đúng:
// GOOD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
2. Bộ Lọc Toàn Cầu Trước Khi Giải Quyết
Bạn có thể đăng ký một bộ lọc toàn cầu với router.beforeResolve
. Điều này tương tự như router.beforeEach
vì nó kích hoạt trên mọi điều hướng, nhưng các bộ lọc giải quyết được gọi ngay trước khi điều hướng được xác nhận, sau khi tất cả các bộ lọc trong thành phần và các thành phần đường dẫn không đồng bộ đã được giải quyết. Dưới đây là một ví dụ đảm bảo rằng người dùng đã cung cấp quyền truy cập vào Camera cho các địa chỉ đường dẫn có thuộc tính tùy chỉnh requiresCamera
:
router.beforeResolve(async to => {
if (to.meta.requiresCamera) {
try {
await askForCameraPermission()
} catch (error) {
if (error instanceof NotAllowedError) {
// ... handle the error and then cancel the navigation
return false
} else {
// unexpected error, cancel the navigation and pass the error to the global handler
throw error
}
}
}
})
router.beforeResolve
là điểm lý tưởng để lấy dữ liệu hoặc thực hiện bất kỳ hoạt động nào khác mà bạn muốn tránh nếu người dùng không thể vào trang.
3. Hooks Toàn Cầu Sau
Bạn cũng có thể đăng ký các hook toàn cầu sau, tuy nhiên, khác với các bộ lọc, các hook này không có chức năng next
và không thể ảnh hưởng đến điều hướng:
router.afterEach((to, from) => {
sendToAnalytics(to.fullPath)
})
Chúng hữu ích cho phân tích, thay đổi tiêu đề của trang, các tính năng về khả năng truy cập như thông báo về trang và nhiều điều khác.
Chúng cũng phản ánh các lỗi điều hướng như là đối số thứ ba:
router.afterEach((to, from, failure) => {
if (!failure) sendToAnalytics(to.fullPath)
})
Tìm hiểu thêm về các lỗi điều hướng trên hướng dẫn của nó.
4. Tiêm vào toàn cầu trong các bộ lọc
Từ Vue 3.3, bạn có thể sử dụng inject()
trong các bộ lọc điều hướng. Điều này hữu ích để tiêm các thuộc tính toàn cầu như các cửa hàng pinia. Bất cứ điều gì được cung cấp bằng app.provide()
cũng có thể truy cập trong router.beforeEach()
, router.beforeResolve()
, router.afterEach()
:
// main.ts
const app = createApp(App)
app.provide('global', 'hello injections')
// router.ts or main.ts
router.beforeEach((to, from) => {
const global = inject('global') // 'hello injections'
// a pinia store
const userStore = useAuthStore()
// ...
})
5. Bộ Lọc Theo Từng Đường Dẫn
Bạn có thể xác định các bộ lọc beforeEnter
trực tiếp trên đối tượng cấu hình của một đường dẫn:
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
Các bộ lọc beforeEnter
chỉ kích hoạt khi nhập vào đường dẫn, chúng không kích hoạt khi params
, query
hoặc hash
thay đổi ví dụ như chuyển từ /users/2
sang /users/3
hoặc từ /users/2#info
sang /users/2#projects
. Chúng chỉ được kích hoạt khi điều hướng từ một đường dẫn khác.
Bạn cũng có thể truyền một mảng các hàm vào beforeEnter
, điều này hữu ích khi tái sử dụng các bộ lọc cho các đường dẫn khác nhau:
function removeQueryParams(to) {
if (Object.keys(to.query).length)
return { path: to.path, query: {}, hash: to.hash }
}
function removeHash(to) {
if (to.hash) return { path: to.path, query: to.query, hash: '' }
}
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: [removeQueryParams, removeHash],
},
{
path: '/about',
component: UserDetails,
beforeEnter: [removeQueryParams],
},
]
Khi làm việc với đường dẫn lồng nhau, cả các đường dẫn cha và con đều có thể sử dụng beforeEnter
. Khi đặt trên một đường dẫn cha, nó sẽ không được kích hoạt khi di chuyển giữa các con có cùng cha. Ví dụ:
const routes = [
{
path: '/user',
beforeEnter() {
// ...
},
children: [
{ path: 'list', component: UserList },
{ path: 'details', component: UserDetails },
],
},
]
beforeEnter
trong ví dụ trên sẽ không được gọi khi di chuyển giữa /user/list
và /user/details
, vì chúng chia sẻ cùng một cha. Nếu chúng ta đặt bộ lọc beforeEnter
trực tiếp trên đường dẫn details
thay vào đó, nó sẽ được gọi khi di chuyển giữa hai đường dẫn đó.
tip Có thể đạt được hành vi tương tự với các bộ lọc theo từng đường dẫn bằng cách sử dụng trường meta của đường dẫn và các bộ lọc điều hướng toàn cầu.
6. Bộ Lọc Trong Các Thành Phần
Cuối cùng, bạn có thể xác định trực tiếp các bộ lọc điều hướng đường dẫn trong các thành phần đường dẫn (những cái được truyền vào cấu hình của router)
Sử Dụng API Tùy Chọn
Bạn có thể thêm các tùy chọn sau vào các thành phần đường dẫn:
– beforeRouteEnter
– beforeRouteUpdate
– beforeRouteLeave
<script>
export default {
beforeRouteEnter(to, from) {
// called before the route that renders this component is confirmed.
// does NOT have access to `this` component instance,
// because it has not been created yet when this guard is called!
},
beforeRouteUpdate(to, from) {
// called when the route that renders this component has changed, but this component is reused in the new route.
// For example, given a route with params `/users/:id`, when we navigate between `/users/1` and `/users/2`,
// the same `UserDetails` component instance will be reused, and this hook will be called when that happens.
// Because the component is mounted while this happens, the navigation guard has access to `this` component instance.
},
beforeRouteLeave(to, from) {
// called when the route that renders this component is about to be navigated away from.
// As with `beforeRouteUpdate`, it has access to `this` component instance.
},
}
</script>
Bộ lọc beforeRouteEnter
KHÔNG có quyền truy cập vào this
, vì bộ lọc được gọi trước khi điều hướng được xác nhận, do đó thành phần mới sẽ chưa được tạo ra.
Tuy nhiên, bạn có thể truy cập vào thể hiện bằng cách truyền một callback vào next
. Callback sẽ được gọi khi điều hướng được xác nhận, và thể hiện của thành phần sẽ được truyền vào callback như là đối số:
beforeRouteEnter (to, from, next) {
next(vm => {
// access to component public instance via `vm`
})
}
Lưu ý rằng beforeRouteEnter
là duy nhất hỗ trợ việc truyền một callback vào next
. Đối với beforeRouteUpdate
và beforeRouteLeave
, this
đã có sẵn, vì vậy việc truyền một callback là không cần thiết và do đó không được hỗ trợ:
beforeRouteUpdate (to, from) {
// just use `this`
this.name = to.params.name
}
Bộ lọc rời thường được sử dụng để ngăn người dùng thoát khỏi đường dẫn một cách vô tình với các chỉnh sửa chưa được lưu. Việc điều hướng có thể bị hủy bỏ bằng cách trả về false
.
beforeRouteLeave (to, from) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (!answer) return false
}
Sử Dụng API Hợp Thức
Nếu bạn viết thành phần của mình bằng cách sử dụng API Hợp Thức, bạn có thể thêm bộ lọc cập nhật và rời bằng cách sử dụng onBeforeRouteUpdate
và onBeforeRouteLeave
tương ứng. Vui lòng tham khảo phần API Hợp Thức để biết thêm chi tiết.
7. Toàn Bộ Quy Trình Giải Quyết Điều Hướng
- Điều hướng được kích hoạt.
- Gọi các hàm bảo vệ beforeRouteLeave trong các component bị hủy kích hoạt.
- Gọi các hàm bảo vệ global beforeEach.
- Gọi các hàm bảo vệ beforeRouteUpdate trong các component được tái sử dụng.
- Gọi beforeEnter trong cấu hình route.
- Giải quyết các component route không đồng bộ.
- Gọi beforeRouteEnter trong các component được kích hoạt.
- Gọi các hàm bảo vệ global beforeResolve.
- Điều hướng được xác nhận.
- Gọi các hook global afterEach.
- Cập nhật DOM được kích hoạt.
- Gọi các callback truyền vào next trong các hàm bảo vệ beforeRouteEnter với các instance đã được khởi tạo.
Trên trang web Cafedev, chúng ta đã khám phá về cách sử dụng các bộ lọc điều hướng trong Vue Router để kiểm soát việc điều hướng trong ứng dụng VueJS. Việc hiểu và sử dụng hiệu quả các navigation guards không chỉ giúp bạn tăng tính linh hoạt mà còn nâng cao trải nghiệm người dùng. Hy vọng rằng thông tin mà chúng tôi chia sẻ đã giúp bạn có cái nhìn rõ ràng hơn về cách làm việc với Router VueJS và navigation guards. Hãy tiếp tục khám phá và phát triển các ứng dụng tuyệt vời trên nền tảng VueJS!
Tham khảo thêm: MIỄN PHÍ 100% | Series tự học Vuejs từ cơ bản tới nâng cao
Các nguồn kiến thức MIỄN PHÍ VÔ GIÁ từ cafedev tại đây
Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của CafeDev để nhận được nhiều hơn nữa:
Chào thân ái và quyết thắng!