"use strict";(self.webpackChunkfes_js=self.webpackChunkfes_js||[]).push([[626],{6254:(n,s,a)=>{a.r(s),a.d(s,{data:()=>p});const p={key:"v-6320961c",path:"/guide/route.html",title:"路由",lang:"zh-CN",frontmatter:{},excerpt:"",headers:[{level:2,title:"路由配置",slug:"路由配置",children:[{level:3,title:"routes",slug:"routes",children:[]},{level:3,title:"mode",slug:"mode",children:[]}]},{level:2,title:"约定式路由",slug:"约定式路由",children:[{level:3,title:"约定规范",slug:"约定规范",children:[]},{level:3,title:"动态路由",slug:"动态路由",children:[]},{level:3,title:"嵌套路由",slug:"嵌套路由",children:[]},{level:3,title:"模糊匹配",slug:"模糊匹配",children:[]},{level:3,title:"扩展路由元信息",slug:"扩展路由元信息",children:[]},{level:3,title:"智能路由",slug:"智能路由",children:[]}]},{level:2,title:"路由跳转",slug:"路由跳转",children:[{level:3,title:"声明式",slug:"声明式",children:[]},{level:3,title:"命令式",slug:"命令式",children:[]}]}],filePathRelative:"guide/route.md",git:{updatedTime:1653450562e3,contributors:[{name:"wanchun",email:"445436867@qq.com",commits:1}]}}},7570:(n,s,a)=>{a.r(s),a.d(s,{default:()=>an});var p=a(6252);const t=(0,p._)("h1",{id:"路由",tabindex:"-1"},[(0,p._)("a",{class:"header-anchor",href:"#路由","aria-hidden":"true"},"#"),(0,p.Uk)(" 路由")],-1),e=(0,p.Uk)("像 Vue 、React 这类框架是用组件化搭建页面,路由解决的是路径到组件的匹配问题。Fes.js 基于 "),o=(0,p._)("code",null,"Vue Router",-1),r=(0,p.Uk)(" 实现的路由,想了解更多的同学可以看看"),l={href:"https://next.router.vuejs.org/",target:"_blank",rel:"noopener noreferrer"},c=(0,p.Uk)("官方文档"),u=(0,p.Uk)("。"),i=(0,p.uE)('

路由配置

在配置文件 .fes.js中通过 router 进行配置。

export default {\n    router: {\n        routes: [],\n        mode: 'hash'\n    }\n}\n
1
2
3
4
5
6

routes

',4),k=(0,p._)("code",null,"routes",-1),b=(0,p.Uk)(" 是配置添加到路由的初始路由列表,格式为路由信息的数组。具体使用参考 "),m={href:"https://next.router.vuejs.org/zh/guide/",target:"_blank",rel:"noopener noreferrer"},d=(0,p.Uk)("Vue Router 文档"),g=(0,p.Uk)(" 中关于路由配置、路由匹配相关内容。"),h=(0,p._)("h3",{id:"mode",tabindex:"-1"},[(0,p._)("a",{class:"header-anchor",href:"#mode","aria-hidden":"true"},"#"),(0,p.Uk)(" mode")],-1),y=(0,p._)("p",null,"创建历史记录的类型:",-1),_=(0,p._)("strong",null,"history",-1),v=(0,p.Uk)(",对应 "),q={href:"https://next.router.vuejs.org/zh/api/#createwebhistory",target:"_blank",rel:"noopener noreferrer"},f=(0,p.Uk)("createWebHistory"),x=(0,p._)("strong",null,"hash",-1),U=(0,p.Uk)(",对应 "),j={href:"https://next.router.vuejs.org/zh/api/#createWebHashHistory",target:"_blank",rel:"noopener noreferrer"},w=(0,p.Uk)("createWebHashHistory"),E=(0,p._)("strong",null,"memory",-1),R=(0,p.Uk)(",对应 "),W={href:"https://next.router.vuejs.org/zh/api/#createWebHashHistory",target:"_blank",rel:"noopener noreferrer"},B=(0,p.Uk)("createMemoryHistory"),H=(0,p.uE)('

默认是hash模式。

约定式路由

约定式路由也叫文件路由,就是不需要手写配置,文件系统即路由,通过目录和文件及其命名分析出路由配置。

约定规范

比如以下文件结构:

pages\n├── index.vue         # 根路由页面 路径为 /\n├── *.vue             # 模糊匹配 路径为 *\n├── a.vue             # 路径 /a\n├── b                 # 文件夹b\n│   ├── index.vue     # 路径 /b\n│   ├── @id.vue       # 动态路由 /b/:id\n│   ├── c.vue         # 路径 /b/c\n│   └── layout.vue    # /b 路径下所有页面公共的布局组件\n└── layout.vue        # 根路由下所有页面共用的布局组件\n
1
2
3
4
5
6
7
8
9
10

编译后会得到以下路由配置:

[\n    {\n        "path": "/",\n        "component": require('@/pages/layout').default,\n        "count": 5,\n        "children": [\n            {\n                "path": "/a",\n                "component": require('@/pages/a').default,\n                "name": "a",\n                "meta": {},\n                "count": 7\n            },\n            {\n                "path": "/b",\n                "component": require('@/pages/b/layout').default,\n                "count": 7,\n                "children": [\n                    {\n                        "path": "/b/c",\n                        "component": require('@/pages/b/c').default,\n                        "name": "b_c",\n                        "meta": {},\n                        "count": 14\n                    },\n                    {\n                        "path": "/b/:id",\n                        "component": require('@/pages/b/@id').default,\n                        "name": "b__id",\n                        "meta": {},\n                        "count": 13\n                    },\n                    {\n                        "path": "/b",\n                        "component": require('@/pages/b/index').default,\n                        "name": "b_index",\n                        "meta": {},\n                        "count": 7\n                    }\n                ]\n            },\n            {\n                "path": "/",\n                "component": require('@/pages/index').default,\n                "name": "index",\n                "meta": {},\n                "count": 5\n            },\n            {\n                "path": "/:pathMatch(.*)",\n                "component": require('@/pages/*').default,\n                "name": "FUZZYMATCH",\n                "meta": {},\n                "count": 3\n            }\n        ]\n    }\n]\n
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

需要注意的是,满足以下任意规则的文件不会被注册为路由

动态路由

Fes.js 里约定以 @ 开头的文件或文件夹映射为动态路由。 比如:

嵌套路由

Fes.js 里约定目录下有 layout.vue 时会生成嵌套路由,以 layout.vue 为该目录的公共父组件,layout.vue 中必须实现 RouterView

比如以下目录结构:

pages\n└── users\n    ├── layout.vue\n    ├── index.vue\n    └── list.vue\n
1
2
3
4
5

会生成路由:

[\n    { \n        path: '/users', component: require('@/pages/users/layout').default,\n        children: [\n            { path: '/users', component: require('@/pages/users/index').default },\n            { path: '/users/list', component: require('@/pages/users/list').default },\n        ]\n    }\n]\n
1
2
3
4
5
6
7
8
9

模糊匹配

',20),F=(0,p.Uk)("Fes.js 下约定文件名为 "),z=(0,p._)("code",null,"*",-1),D=(0,p.Uk)(" 的路由是模糊匹配路由,可以用此特性实现 "),M={href:"https://next.router.vuejs.org/zh/guide/essentials/dynamic-matching.html#%E6%8D%95%E8%8E%B7%E6%89%80%E6%9C%89%E8%B7%AF%E7%94%B1%E6%88%96-404-not-found-%E8%B7%AF%E7%94%B1",target:"_blank",rel:"noopener noreferrer"},A=(0,p.Uk)("404 路由"),C=(0,p.Uk)("。"),V=(0,p.uE)('

比如以下目录结构:

pages\n├── index.vue         # 根路由页面 路径为 /\n└── *.vue             # 模糊匹配 路径为 *\n
1
2
3

会生成路由:

[\n    { \n        path: '/', component: require('@/pages/index').default, count: 5\n    },\n    {\n        path: '/:pathMatch(.*)', component: require('@/pages/**').default, count: 3\n    }\n]\n
1
2
3
4
5
6
7
8

这样,如果访问 /foo/ 不能匹配,会 fallback 到 * 路由,通过 src/pages/*.vue 进行渲染。

扩展路由元信息

我们在定义路由时可以配置meta字段,用来记录一些跟路由相关的信息:

const router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      children: [\n        {\n          path: 'bar',\n          component: Bar,\n          // a meta field\n          meta: { requiresAuth: true }\n        }\n      ]\n    }\n  ]\n})\n
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

接下来我们来配置 meta

',9),Z=(0,p._)("div",{class:"language-vue ext-vue line-numbers-mode"},[(0,p._)("pre",{class:"language-vue"},[(0,p._)("code",null,[(0,p._)("span",{class:"token tag"},[(0,p._)("span",{class:"token tag"},[(0,p._)("span",{class:"token punctuation"},"<"),(0,p.Uk)("config")]),(0,p._)("span",{class:"token punctuation"},">")]),(0,p.Uk)('\n{\n "name": "store",\n "title": "vuex测试"\n}\n'),(0,p._)("span",{class:"token tag"},[(0,p._)("span",{class:"token tag"},[(0,p._)("span",{class:"token punctuation"},"")]),(0,p.Uk)("\n")])]),(0,p._)("div",{class:"line-numbers"},[(0,p._)("span",{class:"line-number"},"1"),(0,p._)("br"),(0,p._)("span",{class:"line-number"},"2"),(0,p._)("br"),(0,p._)("span",{class:"line-number"},"3"),(0,p._)("br"),(0,p._)("span",{class:"line-number"},"4"),(0,p._)("br"),(0,p._)("span",{class:"line-number"},"5"),(0,p._)("br"),(0,p._)("span",{class:"line-number"},"6"),(0,p._)("br")])],-1),I=(0,p._)("div",{class:"language-jsx ext-jsx line-numbers-mode"},[(0,p._)("pre",{class:"language-jsx"},[(0,p._)("code",null,[(0,p._)("span",{class:"token keyword"},"import"),(0,p.Uk)(),(0,p._)("span",{class:"token punctuation"},"{"),(0,p.Uk)(" defineRouteMeta"),(0,p._)("span",{class:"token punctuation"},","),(0,p.Uk)(" useRoute "),(0,p._)("span",{class:"token punctuation"},"}"),(0,p.Uk)(),(0,p._)("span",{class:"token keyword"},"from"),(0,p.Uk)(),(0,p._)("span",{class:"token string"},"'@fesjs/fes'"),(0,p._)("span",{class:"token punctuation"},";"),(0,p.Uk)("\n"),(0,p._)("span",{class:"token function"},"defineRouteMeta"),(0,p._)("span",{class:"token punctuation"},"("),(0,p._)("span",{class:"token punctuation"},"{"),(0,p.Uk)("\n "),(0,p._)("span",{class:"token literal-property property"},"name"),(0,p._)("span",{class:"token operator"},":"),(0,p.Uk)(),(0,p._)("span",{class:"token string"},'"store"'),(0,p._)("span",{class:"token punctuation"},","),(0,p.Uk)("\n "),(0,p._)("span",{class:"token literal-property property"},"title"),(0,p._)("span",{class:"token operator"},":"),(0,p.Uk)(),(0,p._)("span",{class:"token string"},'"vuex测试"'),(0,p.Uk)("\n"),(0,p._)("span",{class:"token punctuation"},"}"),(0,p._)("span",{class:"token punctuation"},")"),(0,p.Uk)("\n")])]),(0,p._)("div",{class:"line-numbers"},[(0,p._)("span",{class:"line-number"},"1"),(0,p._)("br"),(0,p._)("span",{class:"line-number"},"2"),(0,p._)("br"),(0,p._)("span",{class:"line-number"},"3"),(0,p._)("br"),(0,p._)("span",{class:"line-number"},"4"),(0,p._)("br"),(0,p._)("span",{class:"line-number"},"5"),(0,p._)("br")])],-1),G=(0,p._)("div",{class:"language-tsx ext-tsx line-numbers-mode"},[(0,p._)("pre",{class:"language-tsx"},[(0,p._)("code",null,[(0,p._)("span",{class:"token keyword"},"import"),(0,p.Uk)(),(0,p._)("span",{class:"token punctuation"},"{"),(0,p.Uk)(" defineRouteMeta"),(0,p._)("span",{class:"token punctuation"},","),(0,p.Uk)(" useRoute "),(0,p._)("span",{class:"token punctuation"},"}"),(0,p.Uk)(),(0,p._)("span",{class:"token keyword"},"from"),(0,p.Uk)(),(0,p._)("span",{class:"token string"},"'@fesjs/fes'"),(0,p._)("span",{class:"token punctuation"},";"),(0,p.Uk)("\n"),(0,p._)("span",{class:"token function"},"defineRouteMeta"),(0,p._)("span",{class:"token punctuation"},"("),(0,p._)("span",{class:"token punctuation"},"{"),(0,p.Uk)("\n name"),(0,p._)("span",{class:"token operator"},":"),(0,p.Uk)(),(0,p._)("span",{class:"token string"},'"store"'),(0,p._)("span",{class:"token punctuation"},","),(0,p.Uk)("\n title"),(0,p._)("span",{class:"token operator"},":"),(0,p.Uk)(),(0,p._)("span",{class:"token string"},'"vuex测试"'),(0,p.Uk)("\n"),(0,p._)("span",{class:"token punctuation"},"}"),(0,p._)("span",{class:"token punctuation"},")"),(0,p.Uk)("\n")])]),(0,p._)("div",{class:"line-numbers"},[(0,p._)("span",{class:"line-number"},"1"),(0,p._)("br"),(0,p._)("span",{class:"line-number"},"2"),(0,p._)("br"),(0,p._)("span",{class:"line-number"},"3"),(0,p._)("br"),(0,p._)("span",{class:"line-number"},"4"),(0,p._)("br"),(0,p._)("span",{class:"line-number"},"5"),(0,p._)("br")])],-1),L=(0,p.uE)('

则编译后的路由配置为:

[\n    { \n        path: '/a', \n        component: require('@/pages/a').default, \n        meta: {\n            "name": "store",\n            "title": "vuex测试"\n        }\n    },\n]\n




 
 
 
 


1
2
3
4
5
6
7
8
9
10

智能路由

可以看到,编译后路由都会有 count 属性,这是我们根据精准匹配优先算法原则设计出路由排名算法,对匹配到的路由打分:

当我们跳转路由时,如果 URL 匹配到多个路由,则选择分数最高的路由。

路由跳转

',7),O=(0,p.Uk)("想学习更多,可以查看 "),P={href:"https://next.router.vuejs.org/zh/guide/essentials/navigation.html#%E6%9B%BF%E6%8D%A2%E5%BD%93%E5%89%8D%E4%BD%8D%E7%BD%AE",target:"_blank",rel:"noopener noreferrer"},T=(0,p.Uk)("Vue Router 官方文档"),Y=(0,p.Uk)("。"),N=(0,p.uE)('

声明式

<template>\n    <router-link to="/home">Home</router-link>\n</template>\n
1
2
3

命令式

',3),J=(0,p.Uk)("页面跳转 API 由 "),K=(0,p._)("code",null,"router",-1),Q=(0,p.Uk)(" 实例提供,查看 "),S={href:"https://next.router.vuejs.org/zh/api/#router-%E6%96%B9%E6%B3%95",target:"_blank",rel:"noopener noreferrer"},X=(0,p.Uk)("Vue Rouer 文档"),$=(0,p.Uk)("了解更多。"),nn=(0,p.uE)('
import { useRouter } from '@fesjs/fes';\n\nexport default {\n    setup(){\n        const router = useRouter();\n        // 这三种形式是等价的\n        router.push('/users/posva#bio')\n        router.push({ path: '/users/posva', hash: '#bio' })\n        router.push({ name: 'users', params: { username: 'posva' }, hash: '#bio' })\n        // 只改变 hash\n        router.push({ hash: '#bio' })\n        // 只改变 query\n        router.push({ query: { page: '2' } })\n        // 只改变 param\n        router.push({ params: { username: 'jolyne' } })\n\n        // 跳转到上一个路由\n        router.goBack();\n\n        // \b跳转到前一个历史记录\n        router.go(1);\n\n        // 替换历史堆栈中的记录\n        router.replace('/new');\n    }\n}\n\n
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
',1),sn={},an=(0,a(3744).Z)(sn,[["render",function(n,s){const a=(0,p.up)("OutboundLink"),sn=(0,p.up)("CodeGroupItem"),an=(0,p.up)("CodeGroup");return(0,p.wg)(),(0,p.iD)(p.HY,null,[t,(0,p._)("p",null,[e,o,r,(0,p._)("a",l,[c,(0,p.Wm)(a)]),u]),i,(0,p._)("p",null,[k,b,(0,p._)("a",m,[d,(0,p.Wm)(a)]),g]),h,y,(0,p._)("ul",null,[(0,p._)("li",null,[_,v,(0,p._)("a",q,[f,(0,p.Wm)(a)])]),(0,p._)("li",null,[x,U,(0,p._)("a",j,[w,(0,p.Wm)(a)])]),(0,p._)("li",null,[E,R,(0,p._)("a",W,[B,(0,p.Wm)(a)])])]),H,(0,p._)("p",null,[F,z,D,(0,p._)("a",M,[A,(0,p.Wm)(a)]),C]),V,(0,p.Wm)(an,null,{default:(0,p.w5)((()=>[(0,p.Wm)(sn,{title:"vue",active:""},{default:(0,p.w5)((()=>[Z])),_:1}),(0,p.Wm)(sn,{title:"jsx"},{default:(0,p.w5)((()=>[I])),_:1}),(0,p.Wm)(sn,{title:"tsx"},{default:(0,p.w5)((()=>[G])),_:1})])),_:1}),L,(0,p._)("p",null,[O,(0,p._)("a",P,[T,(0,p.Wm)(a)]),Y]),N,(0,p._)("p",null,[J,K,Q,(0,p._)("a",S,[X,(0,p.Wm)(a)]),$]),nn],64)}]])},3744:(n,s)=>{s.Z=(n,s)=>{const a=n.__vccOpts||n;for(const[n,p]of s)a[n]=p;return a}}}]);