一般页面定义好路径之后需要路由来转发到对应的组件上面,路径通常是固定的,比如user.login页面就是指向登录页组件,但如果菜单栏是可以增加和修改的,那么就会出现user/123,user/456,这样的路径,我们不可能在路由表中提前设置,那么这个时候就需要动态的把路由信息写到路由表中
问题
先看下问题,我需要设置一个路由,这个路由是用来通过iframe展示嵌入页的,嵌入的链接都可以正常到iframe页面进行展示,但是会出现下面的问题。
由于配置的都是不同的url,就会出现一个问题,不同的url都走了这个相同的iframe页面,虽然功能上没问题,但是在tabs标签中会被识别为同一个标签页,即使我嵌入两个不同的页面,那么tabs就只会出现一个同样的tab标签
所以这种路由的方式是不可取的,因为每一个页面都会进入相同的路由,并且title是相同的,无法区分嵌入链接都页面,应该按照当前返回的菜单来动态生成我们的路由信息。
动态更新路由PatchRoutes
根据官方文档可以看到能够修改路由表的信息的api
export async function patchRoutes({ routes }) {
console.log('routes123', routes);
}
在这里可以看到已经定义好的静态路由
由于是动态添加路由,所以我们需要整理出菜单中的ifrmae页面,因为这些ifram页面是不确定的,所以只能通过动态的方式加入到路由中
重新梳理下路由信息的定义(可跳过)
后面这一串是要嵌入的地址,但是当前情况下页面会不正常,因为放入的是一个链接,需要进行一下url转码
转码后就能正常现实
但是由于是动态路由,每个的地址都需要不一样,才能在路由表中配置各自的名称,所以上面的办法取的是嵌入地址的路径来作为前置地址,比如嵌入的页面是 .../content/special/static/index.do,那么我生成的路由path就是
{
path: '/iframe/content/special/static/:url',
icon: 'PartitionOutlined',
component: 'bi/analysis/iframe',
wrappers: ['@/components/KeepAlive'],
keppAlive: true,
title: '嵌入页面1',
},
根据我的嵌入的地址去截取,去生成这个path,
如果我有多个的话,就应该是下面这样的路径,其中aaa bbb ccc就是截取的地址,这样才能把各个页面区分开
{
path: '/iframe/content/special/static/:url',
icon: 'PartitionOutlined',
component: 'bi/analysis/iframe',
wrappers: ['@/components/KeepAlive'],
keppAlive: true,
title: '嵌入页面1',
},{
path: '/iframe/ccc/aaa/bbb/:url',
icon: 'PartitionOutlined',
component: 'bi/analysis/iframe',
wrappers: ['@/components/KeepAlive'],
keppAlive: true,
title: '嵌入页面2',
},{
path: '/iframe/ccc111/aaa111/bbb111/:url',
icon: 'PartitionOutlined',
component: 'bi/analysis/iframe',
wrappers: ['@/components/KeepAlive'],
keppAlive: true,
title: '嵌入页面3',
},
但是还要截取,第一个是麻烦,第二个是可能会出现相同路径也不一定,所以直接换成简单点,保证唯一性就直接用时间戳来做地址的前缀
{
path: '/iframe/1728540816447/:url',
icon: 'PartitionOutlined',
component: 'bi/analysis/iframe',
wrappers: ['@/components/KeepAlive'],
keppAlive: true,
title: '嵌入页面1',
},{
path: '/iframe/1728540816427/:url',
icon: 'PartitionOutlined',
component: 'bi/analysis/iframe',
wrappers: ['@/components/KeepAlive'],
keppAlive: true,
title: '嵌入页面2',
},{
path: '/iframe/1728540816437/:url',
icon: 'PartitionOutlined',
component: 'bi/analysis/iframe',
wrappers: ['@/components/KeepAlive'],
keppAlive: true,
title: '嵌入页面3',
},
个人感觉这样会简洁很多
现在静态路由中是这样的
两个固定的路由,并且指向同一个组件,但是可以生成两个不同名称的标签页,同时根据url来嵌入到页面的iframe中
接下来要做的事情就是将这两路由在页面加载的时候通过umi的patchRoutes,去动态的生成并且插入到路由表中,因为菜单是用户自己加的,并不知道用户要插入什么链接,所以无法提前预设静态路由
PatchRoutes功能实现
如果要动态的生成路由表,Umi提供了一个api在app.tsx的时候供我们插入路由信息,参数routes打印的就路由表,可以直接通过unshift插入路由信息去改变
export async function patchRoutes({ routes }) {
console.log('routes123', routes);
}
在PatchRoutes这个函数中打印一下routes,也就是路由表
可以看到静态路由中的两个路由是出现在这里的
现在我们把路由表的这两个静态路由注释掉
在patchRoutes中加入这两个试试
export async function patchRoutes({ routes }) {
console.log('routes123', routes);
// const menus = await getRoutersInfo();
const menuRoutes = routes[1]?.routes; // 确认routes[0]是否有嵌套的routes
// if (Array.isArray(menuRoutes)) {
let id = menuRoutes.findIndex((item)=>{
return item.path == "/iframe"
})
// console.log('iframeRouter', iframeRouter);
// iframeRouter[0].children
menuRoutes[id].routes.unshift({
path: '/iframe/1728542330024/:url',
icon: 'PartitionOutlined',
component: 'bi/analysis/iframe',
wrappers: ['@/components/KeepAlive'],
keppAlive: true,
title: '进阶分析2',
}
// {
// path: '/iframe/1728542591255/:url',
// icon: 'PartitionOutlined',
// component: 'bi/analysis/iframe',
// wrappers: ['@/components/KeepAlive'],
// keppAlive: true,
// title: '进阶分析1',
// }
);
// }
console.log('menuRoutes', menuRoutes);
}
可以插入,但是出现问题
可能是写法的问题,在patchroute中不能那么写,先看看放开一个静态和加入一个动态的后,生成的路由信息有什么区别
可以看到上面这个是动态插入的,component这块和下面的静态路由信息有区别
顺便看了一眼原来人家官方是这样写的,那我们也改一下
用require的方法直接启动不了项目,不知道是什么情况
component: () => import('./pages/bi/analysis/iframe')
改用成这个貌似也不行
直接来换个思路,定义一个静态路由例子,直接拿静态路由里面的数据的component
export async function patchRoutes({ routes }) {
console.log('routes123', routes);
const menuRoutes = routes[1]?.routes; // 确认routes[0]是否有嵌套的routes
// if (Array.isArray(menuRoutes)) {
let id = menuRoutes.findIndex((item)=>{
return item.path == "/iframe"
})
// console.log('iframeRouter', iframeRouter);
menuRoutes[id].routes.unshift({
path: '/iframe/1728542330024/:url',
icon: 'PartitionOutlined',
component: menuRoutes[id].routes[0].component,
wrappers: menuRoutes[id].routes[0].wrappers,
keppAlive: true,
title: '进阶分析2',
}
);
// }
console.log('menuRoutes', menuRoutes);
}
menuRoutes[id].routes[0].component 直接拿到静态路由的component来生成动态路由,因为指向的component都是相同的,先用这个笨办法先
处理完成,直接修改了路由表中的内容
下面这份是菜单数据
可以看到我们新建的菜单,链接都做了转码的处理,并且有时间戳去规定唯一标识,我新建多少个菜单,都可以对应生成多少个路由
这样的好处是即使每个带有链接都菜单都是用的iframe这个组件页面,但是我在tabs中可以区分开他们,不然会被识别成同一个路由,切换不了tab,而且应用成功后tab的名称就是菜单的名称
最后结果
最后路由也是根据菜单中带有iframe标识的路径生成了两个
分别访问
/bi/analysis/iframe/http%3A%2F%2Flocalhost%3A18080%2Fbi_portal7_3_16_war_exploded%2Fcontent%2Forder%2Fdue%2Findex.do
和
/bi/analysis/iframe/http%3A%2F%2Flocalhost%3A18080%2Fbi_portal7_3_16_war_exploded%2Fcontent%2Fspecial%2Fstatic%2Findex.do
能够出现自己的title,并且tab页也能正确的区分开是两个路由