Closed kids-return closed 3 years ago
ProLayout 会根据 location.pathname 来自动选中菜单,并且自动生成相应的面包屑。如果不想使用可以自己配置 selectedKeys 和 openKeys 来进行受控配置。
selectedKeys 和 parentKeys 之间有什么关系 parentKeys 在何种情况下才会生效 selectedKeys,没找到在哪里设置, 我还是小白水平,这个问题 困扰我好久了
使用的是 v5 "@ant-design/pro-layout": "^6.4.19",
export const layout = ({
initialState,
}: {
initialState: {
settings?: LayoutSettings;
currentUser?: API.CurrentUser;
menus?: any; // 应该是 MenuDataItem[]
};
}): BasicLayoutProps => {
console.log('app.initialState', initialState);
return {
rightContentRender: () => <RightContent />,
disableContentMargin: false,
footerRender: () => <Footer />,
onPageChange: () => {
const { currentUser } = initialState;
const { location } = history;
// 如果没有登录,重定向到 login
if (!currentUser && location.pathname !== '/user/login') {
history.push('/user/login');
}
},
menuHeaderRender: undefined,
menuDataRender: (): MenuDataItem[] => {
const { menus } = initialState;
return menus;
},
...initialState?.settings,
};
};
ProLayout 会根据 location.pathname 来自动选中菜单,并且自动生成相应的面包屑。如果不想使用可以自己配置 selectedKeys 和 openKeys 来进行受控配置。
我使用这种方式成功了 但面包屑还是根据 pathname 来进行匹配的 parentKeys 要在什么场景下使用呢
如果能通过 parentKeys 实现应该会更好,不然好繁琐呀
建议路由和菜单分开,路由做路由的事,菜单做菜单的事,面包屑和菜单绑定 对于用户来说无非是多定义一个菜单文件,动态菜单,动态路由实现起来更方便,结构更清晰。 我排查菜单的问题 还是路由的问题 排查了几个小时,对于我这种新手来说太难了
我不确定 parentKeys 在哪种场景下使用,初步判断是路由和菜单结合才会生效,因为我分开他们一直没生效过
@chenshuai2144 大佬能帮我看一下吗,我从早上折腾到现在了 😢
其实我没看懂你要干什么
我想知道菜单的 parentKeys 在什么情况下生效 @chenshuai2144
我目前是后台获取的动态菜单
-/a
-/a/b/c <-选中时
-/a/b <-自动选中
通过 selectedKeys,和 openKeys 自己写逻辑可以解决,但面包屑 还是 /a /a/b /a/b/c
所以在动态菜单的情况下,要如何使 parentKeys 生效,由开发者自己控制选中哪个菜单
父子菜单要当成平级使用吗?
因为是后台控制的呀,后台需要和 RBAC 权限捆绑实现动态菜单,然后希望调整菜单层级的时候不修改后台和前台的路由
我原本以为可以通过 菜单的 parentKeys 实现,但一直不生效 所以就想知道 parentKeys 使用的场景
可以理解我强制把 三级的 /a/b/c 修改到 二级 /a 下面, 返回的动态菜单的 children 也在 /a 的里面
{
path: "/a"
children: [
{path:"/a/b", parentKeys:["/a"]},
{path:"/a/b/c", parentKeys:["/a"]},
]
}
类似这样,后台可以动态调整 各种层级关系,前后台路由不变,我原本以为可以通过 parentKeys 来实现父级菜单的选中 但不行
因为是动态菜单,各种层级关系调整是避免不了的 例如调整成这种关系
{
path: "/a/b/c"
children: [
{path:"/a/b", parentKeys:["/a/b/c"]},
{path:"/a", parentKeys:["/a/b/c"]},
]
}
我期望通过 parentKeys 来决定选中的上级 而不是 pathname
你打破了prolayout的约定 有个黑科技我明给你写个demo,如果没有层级关系还是不要包含了
后台是个无限级的树,可以各种调整层级 返回对应的 children
所以我就想知道 parentKeys 在什么情况下生效,因为这个后端会一起返回过来告诉我上级是什么
我有通过 selectedKeys 和 openKeys 写逻辑实现效果,但面包屑依然还是无法改变。 我本以为按照官方的最佳思路 parentKeys 可以解决 但是测试了很久依然解决不了
这种情况下就不知道 parentKeys 在哪种情境下可以生效 然后延伸出 如果 routes 和 menu 分开 可能对用户更友好,我瞎猜的
后台的逻辑 是 判断用户的所有权限列表和菜单的匹配、如果权限和菜单的地址匹配就显示这个菜单 权限列表是后台的 restful 标准的 api 地址
如果调整层级 需要修改权限列表和后台 API 路由 我认为不符合最佳实践 所以一直测试 parentKeys
https://procomponents.ant.design/components/layout/ 我都要哭了 我真的不知道通过这个 parentKeys 如何控制选中的情况
app.js
export const layout = ({
initialState,
setInitialState,
}: {
initialState: {
settings?: LayoutSettings;
currentUser?: API.CurrentUser;
menus?: any; // 应该是 MenuDataItem[]
};
}): BasicLayoutProps => {
console.log('app.initialState', initialState, setInitialState);
return {
rightContentRender: () => <RightContent />,
disableContentMargin: false,
footerRender: () => <Footer />,
onPageChange: () => {
const { currentUser } = initialState;
const { location } = history;
// 如果没有登录,重定向到 login
if (!currentUser && location.pathname !== '/user/login') {
history.push('/user/login');
}
},
menuHeaderRender: undefined,
menuDataRender: (): MenuDataItem[] => {
const { menus } = initialState;
return menus;
},
menuProps: {
selectedKeys: initialState?.selectedKeys,
openKeys: initialState?.openKeys,
onSelect: ({item, key, keyPath, domEvent}) => {
const { openKeys } = initialState
console.log(openKeys.length);
setInitialState({...initialState, selectedKeys: keyPath});
if (openKeys.length > 1) {
setInitialState({...initialState, openKeys: [openKeys.pop()]});
}
console.log('onClick', item, keyPath);
},
onOpenChange: (openKeys) => {
setInitialState({...initialState, openKeys});
console.log('onOpenChange', openKeys);
},
},
...initialState?.settings,
};
};
我通过 menuProps 可以实现,但是面包屑依然是一样的问题 就想搞明白 parentKeys 的使用情况
parentKeys 是混合的,可以强行设置,但是原来的还会再。
[...defaultKeys,...parentKeys ], 最好的解决办法是让后端按照规范来处理菜单,或者猛一点自己的实现菜单的openKeys
我已经通过上面的代码实现 openKeys 菜单了,然而 面包屑
还会有同样的问题,面包屑
会自动根据 path 里的 /
进行分割
如果后端修改的话 所有的菜单地址里都不能出现 /
分割符,所有的地址都需要改为这样 a
a-b
a-b-c
a-b-c-d
有没有可能设置这个分隔符为别的,或完全关闭
其实也就是分隔符的问题
我排查的思路和想要的效果如下
那么只需要通过 parentKeys 来控制层级关系即可
重复提交 同样的issue ,污染社区的话,我会拉黑并删除你
你的需求不适合使用prolayout,我建议你全部自己控制。 面包屑可以用 breadcrumbRender={()=>[]} 关闭,如果你不打算遵守重型组件的约定,那么重型组件对你来说是个负担,不会给你任何提效
@chenshuai2144 我是为了把三个问题 单独抽离出来方便查看,我不确定三个问题是否属于同一个,上面感觉比较混乱
遵循约定,当我 /a/b/c/d 有一天要调整到第二级 就需要把菜单地址修改为 /a/b-c-d,对应的是前端的路由也需要修改和重新打包 只要一修改菜单层级遵守约定的话对应的都要修改,要么就全部的路由都要定义为 /a-b-c-d 这种,不然无法满足后台获取菜单 及菜单层级调整
export default [
{
path: '/',
name: 'welcome',
children: [
{
path: '/welcome',
name: 'one',
children: [
{
path: '/welcome/welcome', <- 这里
name: 'two',
exact: true,
},
],
},
],
},
{
path: '/demo',
name: 'demo',
},
];
export default [
{
path: '/',
name: 'welcome',
children: [
{
path: '/welcome',
name: 'one',
},
],
},
{
path: '/welcome-welcome', <- 这里
name: 'two',
exact: true,
},
{
path: '/demo',
name: 'demo',
},
];
例如这是根据demo通过服务器获取的 当服务器调整的层级 准守约定的话 需要做如下
/welcome/welcome
到 一个非自动匹配 path 如 /welcome-welcome
/welcome/welcome
到 /welcome-welcome
服务器获取的菜单无法调整的情况下,服务器获取就没有意义呀,调整都是要打包的 不如直接写前端
这是 fork 官方的服务器获取菜单的例子 https://codesandbox.io/s/wispy-monad-uc33n?file=/customMenu.ts
你的这种场景全部的path 都改成 a-b-c ,选中用 parentsKeys 来实现,这样就不用重型组件自己的选中了
好的 感谢,我决定再学习研究一段时间,改写 pro-layout 组件,将菜单和路由分开 我认为菜单和路由没必要耦合在一起,路由负责路由的事,菜单负责菜单和面包屑的事情,菜单默认开启 路径匹配,关闭路径匹配后通过菜单的 chilren 决定菜单和面包屑的层级关系 我是这么构思的,目前能力还达不到,刚接触不久,就是想做一个后台RBAC + 后台动态菜单的管理功能,太难了
很多项目达不到这样的复杂度的。刚开始选型的时候纠结过,不过我们选择了适合大多数人的一套
再次感谢,我一直认为是可能实现的,是我不会使用的问题,现在已经明确下一步方向了
@kids-return ,最后搞定了吗,我也遇到了这种情况……
app.js
export const layout = ({ initialState, setInitialState, }: { initialState: { settings?: LayoutSettings; currentUser?: API.CurrentUser; menus?: any; // 应该是 MenuDataItem[] }; }): BasicLayoutProps => { console.log('app.initialState', initialState, setInitialState); return { rightContentRender: () => <RightContent />, disableContentMargin: false, footerRender: () => <Footer />, onPageChange: () => { const { currentUser } = initialState; const { location } = history; // 如果没有登录,重定向到 login if (!currentUser && location.pathname !== '/user/login') { history.push('/user/login'); } }, menuHeaderRender: undefined, menuDataRender: (): MenuDataItem[] => { const { menus } = initialState; return menus; }, menuProps: { selectedKeys: initialState?.selectedKeys, openKeys: initialState?.openKeys, onSelect: ({item, key, keyPath, domEvent}) => { const { openKeys } = initialState console.log(openKeys.length); setInitialState({...initialState, selectedKeys: keyPath}); if (openKeys.length > 1) { setInitialState({...initialState, openKeys: [openKeys.pop()]}); } console.log('onClick', item, keyPath); }, onOpenChange: (openKeys) => { setInitialState({...initialState, openKeys}); console.log('onOpenChange', openKeys); }, }, ...initialState?.settings, }; };
我通过 menuProps 可以实现,但是面包屑依然是一样的问题 就想搞明白 parentKeys 的使用情况
不好用啊,item, key, keyPath, domEvent都是 undefined
@kids-return 怎么实现的的,不好用啊
🧐 问题描述
通过后台获取的动态菜单 菜单格式
当选中 /a/b/c 时 /a/b 也会选中,还是会进行 pathname 匹配。 因为菜单是后台动态控制的,希望可以随意调整层级的情况下 path 不改变