路由
像 Vue 、React 这类框架是用组件化搭建页面,路由解决的是路径到组件的匹配问题。Fes.js 基于 Vue Router
实现的路由,想了解更多的同学可以看看官方文档。
路由配置
在配置文件 .fes.js
中通过 router
进行配置。
export default {
router: {
routes: [],
mode: 'hash',
},
};
routes
routes
是配置添加到路由的初始路由列表,格式为路由信息的数组。具体使用参考 Vue Router 文档 中关于路由配置、路由匹配相关内容。
mode
创建历史记录的类型:
- history,对应 createWebHistory
- hash,对应 createWebHashHistory
- memory,对应 createMemoryHistory
默认是hash
模式。
约定式路由
约定式路由也叫文件路由,就是不需要手写配置,文件系统即路由,通过目录和文件及其命名分析出路由配置。
约定规范
比如以下文件结构:
pages
├── index.vue # 根路由页面 路径为 /
├── [...slug].vue # 模糊匹配 路径为 /:slug(.*)
├── a.vue # 路径 /a
├── b # 文件夹b
│ ├── index.vue # 路径 /b
│ ├── [slug].vue # 动态路由 /b/:slug
│ ├── c.vue # 路径 /b/c
│ └── layout.vue # /b 路径下所有页面公共的布局组件
└── layout.vue # 根路由下所有页面共用的布局组件
编译后会得到以下路由配置:
[
{
path: '/',
component: require('@/pages/layout').default,
count: 5,
children: [
{
path: '/a',
component: require('@/pages/a').default,
name: 'a',
meta: {},
count: 7,
},
{
path: '/b',
component: require('@/pages/b/layout').default,
count: 7,
children: [
{
path: '/b/c',
component: require('@/pages/b/c').default,
name: 'b_c',
meta: {},
count: 14,
},
{
path: '/b/:id',
component: require('@/pages/b/@id').default,
name: 'b__id',
meta: {},
count: 13,
},
{
path: '/b',
component: require('@/pages/b/index').default,
name: 'b_index',
meta: {},
count: 7,
},
],
},
{
path: '/',
component: require('@/pages/index').default,
name: 'index',
meta: {},
count: 5,
},
{
path: '/:pathMatch(.*)',
component: require('@/pages/*').default,
name: 'FUZZYMATCH',
meta: {},
count: 3,
},
],
},
];
需要注意的是,满足以下任意规则的文件不会被注册为路由:
- 不是
.vue .jsx
文件 components
目录中的文件
动态路由
Fes.js 里约定名称为 [slug]
格式的文件或文件夹映射为动态路由。 比如:
src/pages/users/[id].vue
会成为/users/:id
src/pages/users/[id]/settings.vue
会成为/users/:id/settings
WARNING
@slug
形式下版本会弃用,请替换为[slug]
~
模糊匹配
Fes.js 里约定名称为 [...slug]
格式的文件或文件夹映射为动态路由中的模糊匹配形式。 比如:
src/pages/users/[...].vue
会成为/users/:pathMatch(.*)
src/pages/users/[...id].vue
会成为/users/:id(.*)
src/pages/users/[...id]/settings.vue
会成为/users/:id(.*)/settings
WARNING
*
形式下版本会弃用,请替换为[...slug]
~
嵌套路由
Fes.js 里约定目录下有 layout.vue
时会生成嵌套路由,以 layout.vue
为该目录的公共父组件,layout.vue
中必须实现 RouterView
比如以下目录结构:
pages
└── users
├── layout.vue
├── index.vue
└── list.vue
会生成路由:
[
{
path: '/users',
component: require('@/pages/users/layout').default,
children: [
{ path: '/users', component: require('@/pages/users/index').default },
{ path: '/users/list', component: require('@/pages/users/list').default },
],
},
];
模糊匹配
Fes.js 下约定文件名为 *
的路由是模糊匹配路由,可以用此特性实现 404 路由。
比如以下目录结构:
pages
├── index.vue # 根路由页面 路径为 /
└── *.vue # 模糊匹配 路径为 *
会生成路由:
[
{
path: '/',
component: require('@/pages/index').default,
count: 5,
},
{
path: '/:pathMatch(.*)',
component: require('@/pages/**').default,
count: 3,
},
];
这样,如果访问 /foo
,/
不能匹配,会 fallback 到 *
路由,通过 src/pages/*.vue
进行渲染。
智能路由
可以看到,编译后路由都会有 count
属性,这是我们根据精准匹配优先算法原则设计出路由排名算法,对匹配到的路由打分:
- 路由的路径每个子项得到 4 分
- 子项为静态细分(
/list
)再加 3 分 - 子项为动态细分(
/:orderId
)再加 2 分 - 根段(
/
)再 1 分 - 通配符(
*
)匹配到的减去 1 分
当我们跳转路由时,如果 URL 匹配到多个路由,则选择分数最高的路由。
扩展路由元信息
我们在定义路由时可以配置meta
字段,用来记录一些跟路由相关的信息:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
children: [
{
path: 'bar',
component: Bar,
// a meta field
meta: { requiresAuth: true },
},
],
},
],
});
我们使用defineRouteMeta
配置 meta
:
import { defineRouteMeta } from '@fesjs/fes';
defineRouteMeta({
name: 'store',
title: 'vuex测试',
});
当然在单文件组件中,还可以通过<config></config>
配置 meta
:
<config>
{
"name": "store",
"title": "vuex测试"
}
</config>
TIP
推荐使用defineRouteMeta
,有更好的提示。
路由元信息在编译后会附加到路由配置中:
[
{
path: '/a',
component: require('@/pages/a').default,
meta: {
"name": "store",
"title": "vuex测试"
}
},
]
路由跳转
想学习更多,可以查看 Vue Router 官方文档。
声明式
<template>
<router-link to="/home">Home</router-link>
</template>
命令式
页面跳转 API 由 router
实例提供,查看 Vue Rouer 文档了解更多。
import { useRouter } from '@fesjs/fes';
export default {
setup() {
const router = useRouter();
// 这三种形式是等价的
router.push('/users/posva#bio');
router.push({ path: '/users/posva', hash: '#bio' });
router.push({ name: 'users', params: { username: 'posva' }, hash: '#bio' });
// 只改变 hash
router.push({ hash: '#bio' });
// 只改变 query
router.push({ query: { page: '2' } });
// 只改变 param
router.push({ params: { username: 'jolyne' } });
// 跳转到上一个路由
router.goBack();
// 跳转到前一个历史记录
router.go(1);
// 替换历史堆栈中的记录
router.replace('/new');
},
};