Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛[BUG] 从服务端请求菜单时 icon 和 access 不生效 #8101

Closed
lin-mt opened this issue Feb 19, 2021 · 41 comments
Closed

🐛[BUG] 从服务端请求菜单时 icon 和 access 不生效 #8101

lin-mt opened this issue Feb 19, 2021 · 41 comments

Comments

@lin-mt
Copy link

lin-mt commented Feb 19, 2021

🐛 bug 描述

https://beta-pro.ant.design/docs/advanced-menu-cn

根据该文档的方式实现从服务端请求菜单,返回的菜单中包含 icon 信息和 accss 信息,icon 显示错误,access 不生效。

icon显示结果:
image

access无效。

📷 复现步骤

返回的菜单信息:
path: '/system',
name: 'system',
icon: 'setting',
access: 'noPermission',

🏞 期望结果

显示设置的icon,access 生效

💻 复现代码

© 版本信息

  • Ant Design Pro 版本: 5.0.0-beta.2
  • umi 版本
  • 浏览器环境
  • 开发环境 [e.g. mac OS]

🚑 其他信息

@chenshuai2144
Copy link
Collaborator

icon 只能用 dom,access 必须要触发页面的重新渲染才有用

@chengzequn
Copy link

chengzequn commented Mar 8, 2021

你是缺少 @ant-design/icons 图标组件包吧?
安装方法npm install --save @ant-design/icons
我测试
{ path: '/welcome', name: 'welcome', icon: 'setting', component: './Admin', },
是可以用的
image

@chenshuai2144
Copy link
Collaborator

服务器请求回来应该自己处理,是不会走到插件的逻辑的。
权限的请求reload 可以实现,但是菜单不行

@sunfuyue
Copy link

能不能给个详细的icon使用dom渲染的方法,我尝试了下,没成功

@sunfuyue
Copy link

icon 只能用 dom,access 必须要触发页面的重新渲染才有用

能否给点儿详细的代码提示,我将menu数据中的icon字段直接替换成 dom,不生效

@sunfuyue
Copy link

sunfuyue commented Apr 14, 2021

在utils中封装了一个方法;

`import React from 'react';
import { MenuDataItem } from '@ant-design/pro-layout';
import * as allIcons from '@ant-design/icons';

// FIX从接口获取菜单时icon为string类型
const fixMenuItemIcon = (menus: MenuDataItem[], iconType = 'Outlined'): MenuDataItem[] => {
  menus.forEach((item) => {
    const { icon, children } = item;
    if (typeof icon === 'string') {
      let fixIconName = icon.slice(0, 1).toLocaleUpperCase() + icon.slice(1) + iconType;
      item.icon = React.createElement(allIcons[fixIconName] || allIcons[icon]);
    }
    children && children.length > 0 ? (item.children = fixMenuItemIcon(children)) : null;
  });
  return menus;
};

export default fixMenuItemIcon;`

在layout组件中直接调用
`menuDataRender={() => fixMenuItemIcon(menus.menusData)}`

就能解决了

@chenshuai2144
Copy link
Collaborator

你的这个代码会导致 js 大小增加 2m 左右,要慎重

@sunfuyue
Copy link

请问怎么更优雅的解决呢?

@lishaoh
Copy link

lishaoh commented Apr 28, 2021

菜单access怎么解决呢

@strongyc
Copy link

strongyc commented Jul 5, 2021

有啥好的解决办法么,解决服务器请求菜单设置icon图标

@chenshuai2144
Copy link
Collaborator

#8101

@Zeng-Jun-Wei
Copy link

@chenshuai2144 同问该怎么优雅的解决icon

@chengzi-code
Copy link

用了个死办法,枚举

import {
  BookOutlined,
  LinkOutlined,
  AppstoreOutlined,
  SmileOutlined,
  TableOutlined,
  SoundOutlined,
  CrownOutlined,
} from '@ant-design/icons';

// 利用对象进行图标映射
const iconMapping = {
  AppstoreOutlined: <AppstoreOutlined />,
  SmileOutlined: <SmileOutlined />,
  TableOutlined: <TableOutlined />,
  SoundOutlined: <SoundOutlined />,
  CrownOutlined: <CrownOutlined />
}


   menu: {
      params: initialState,
      // 这里从后端请求动态菜单
      request: async (params, defaultMenuData) => {

        // 这里返回后端的菜单配置  forEach? 把icon字符串 转化为 render图标
        params?.currentUser?.reqMemu.forEach((item: any) => item.icon = iconMapping[item.icon])
        return params?.currentUser?.reqMemu;
      },
    },

@Zeng-Jun-Wei
Copy link

用了个死办法,枚举

import {
  BookOutlined,
  LinkOutlined,
  AppstoreOutlined,
  SmileOutlined,
  TableOutlined,
  SoundOutlined,
  CrownOutlined,
} from '@ant-design/icons';

// 利用对象进行图标映射
const iconMapping = {
  AppstoreOutlined: <AppstoreOutlined />,
  SmileOutlined: <SmileOutlined />,
  TableOutlined: <TableOutlined />,
  SoundOutlined: <SoundOutlined />,
  CrownOutlined: <CrownOutlined />
}


   menu: {
      params: initialState,
      // 这里从后端请求动态菜单
      request: async (params, defaultMenuData) => {

        // 这里返回后端的菜单配置  forEach? 把icon字符串 转化为 render图标
        params?.currentUser?.reqMemu.forEach((item: any) => item.icon = iconMapping[item.icon])
        return params?.currentUser?.reqMemu;
      },
    },

得枚举很大一部分... @chengzi-code

@Loomark
Copy link

Loomark commented Aug 24, 2021

所以这么问题优雅的解决了吗

@kevinsheep
Copy link

icon 不显示的问题,可以自定义菜单项渲染方法,并引用自定义的图标库
看到这个问题被关闭,并标记为Feature Request,不知道以后是否有官方解决方案。
我的方案如下:

// MenuItemRender.tsx,`app.tsx`直接引用即可
import { MenuDataItem } from '@ant-design/pro-layout';
import { createFromIconfontCN } from '@ant-design/icons';
import { Link, useIntl } from 'umi';

let IconFont = createFromIconfontCN({
  // 以下是默认值,也可以按需要指定
  // scriptUrl: defaultSettings.iconfontUrl,
});

const getIcon = (
  icon?: string | React.ReactNode,
  iconPrefixes: string = 'icon-',
): React.ReactNode => {
  if (typeof icon === 'string' && icon !== '') {
    // 可加入多种图标类型的兼容写法,此处省略
    if (icon.startsWith(iconPrefixes)) {
      return <IconFont type={icon} className={icon} />;
    }
  }
  return icon;
};

const MenuItem: React.FC<MenuDataItem> = (menuItemProps) => {
  const { formatMessage } = useIntl();
  const { isUrl: isLink, path, icon, locale } = menuItemProps;
  const localeStr = locale as string; // 和 `formatMessage中` 的 `id` 类型不一致,只好断言一下
  const itemContent = (
    <span className="ant-pro-menu-item">
      {getIcon(icon)}
      <span className="ant-pro-menu-item-title">{formatMessage({ id: localeStr })}</span>
    </span>
  );
  return isLink || !path || location.pathname === path ? (
    itemContent
  ) : (
    <Link to={path}>{itemContent}</Link>
  );
};

export default MenuItem;

还是想用 Ant Design 的图标库?拿去吧:https://www.iconfont.cn/collections/detail?cid=9402

@Zeng-Jun-Wei
Copy link

Zeng-Jun-Wei commented Aug 25, 2021

 // app.tsx
 export const layout: RunTimeLayoutConfig = ({ initialState }) => {
   return {
       rightContentRender: () => <RightContent />,
       disableContentMargin: false,
       onPageChange: () => {
          const { location } = history;
         // 如果没有登录,重定向到 login
        if (!initialState?.currentUser && location.pathname !== loginPath) {
            history.push(loginPath);
        }
     },
     ...initialState?.settings,
     menuDataRender: () => {
        if (initialState?.menus) {
           return initialState.menus;
        }
        return [];
     },
    menuItemRender: (menuItemProps: MenuDataItem) => {
        return <MenuItemRender {...menuItemProps} />;
    }
   }
 };
// 菜单
 {
    path: '/welcome',
    name: 'welcome',
    icon: 'smile',
    component: './Welcome'
  },
  {
    path: '/admin',
    name: 'admin',
    icon: 'crown',
    access: 'canAdmin',
    component: './Admin',
    routes: [
      {
        path: '/admin/sub-page',
        name: 'sub-page',
        icon: 'smile',
        component: './Welcome'
      },
      {
        component: './404'
      }
    ]
  },
  {
    name: 'list.table-list',
    icon: 'table',
    path: '/list',
    component: './TableList'
  },

@kevinsheep 是写法问题吗?iconPrefixes 的判断也去掉了,菜单加载出来一直是一个路径...
image

@kevinsheep
Copy link

kevinsheep commented Aug 26, 2021

@kevinsheep 是写法问题吗?iconPrefixes 的判断也去掉了,菜单加载出来一直是一个路径...

确认一下,icon中的名称,与你的图标库中对应图标命名完全一致(大小写敏感)

@Zeng-Jun-Wei
Copy link

@kevinsheep 是写法问题吗?iconPrefixes 的判断也去掉了,菜单加载出来一直是一个路径...

确认一下,icon中的名称,与你的图标库中对应图标命名完全一致(大小写敏感)

引用的就是Ant Design 的图标库

@kevinsheep
Copy link

@kevinsheep 是写法问题吗?iconPrefixes 的判断也去掉了,菜单加载出来一直是一个路径...

确认一下,icon中的名称,与你的图标库中对应图标命名完全一致(大小写敏感)

引用的就是Ant Design 的图标库

~\config\defaultSettings.ts iconfontUrl 怎么设置的?完整点的代码贴一下?

@Zeng-Jun-Wei
Copy link

defaultSettings

scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js' 。
基本上的代码就是楼上贴的了呀,主要是app.tsx里面调用menuItemRender

@kevinsheep
Copy link

scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js' 。

对比你的字库文件和菜单设置中的icon名称,问题应该是你的图标字库文件内容:
那些叫smile,crown的图标,一个都找不到,并且留意到你的图标名称是以icon为前缀的

@Zeng-Jun-Wei
Copy link

Zeng-Jun-Wei commented Aug 30, 2021

scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js' 。

对比你的字库文件和菜单设置中的icon名称,问题应该是你的图标字库文件内容:
那些叫smile,crown的图标,一个都找不到,并且留意到你的图标名称是以icon为前缀的

用的是 Ant Design 的图标库,加上icon- 也不行
image

@kevinsheep
Copy link

scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js' 。
用的是 Ant Design 的图标库,加上icon- 也不行

你在这个js中搜索一下,有没有一个叫’icon-smile‘的图标名?

@Zeng-Jun-Wei
Copy link

scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js' 。
用的是 Ant Design 的图标库,加上icon- 也不行

你在这个js中搜索一下,有没有一个叫’icon-smile‘的图标名?

我以为这个链接时 antd 的图标库...里面没有smile的图标

@junyunlife
Copy link

在utils中封装了一个方法;

`import React from 'react';
import { MenuDataItem } from '@ant-design/pro-layout';
import * as allIcons from '@ant-design/icons';

// FIX从接口获取菜单时icon为string类型
const fixMenuItemIcon = (menus: MenuDataItem[], iconType = 'Outlined'): MenuDataItem[] => {
  menus.forEach((item) => {
    const { icon, children } = item;
    if (typeof icon === 'string') {
      let fixIconName = icon.slice(0, 1).toLocaleUpperCase() + icon.slice(1) + iconType;
      item.icon = React.createElement(allIcons[fixIconName] || allIcons[icon]);
    }
    children && children.length > 0 ? (item.children = fixMenuItemIcon(children)) : null;
  });
  return menus;
};

export default fixMenuItemIcon;`

在layout组件中直接调用
`menuDataRender={() => fixMenuItemIcon(menus.menusData)}`

就能解决了

scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js' 。
用的是 Ant Design 的图标库,加上icon- 也不行

你在这个js中搜索一下,有没有一个叫’icon-smile‘的图标名?

我以为这个链接时 antd 的图标库...里面没有smile的图标

@Zeng-Jun-Wei
Copy link

在utils中封装了一个方法;

`import React from 'react';
import { MenuDataItem } from '@ant-design/pro-layout';
import * as allIcons from '@ant-design/icons';

// FIX从接口获取菜单时icon为string类型
const fixMenuItemIcon = (menus: MenuDataItem[], iconType = 'Outlined'): MenuDataItem[] => {
  menus.forEach((item) => {
    const { icon, children } = item;
    if (typeof icon === 'string') {
      let fixIconName = icon.slice(0, 1).toLocaleUpperCase() + icon.slice(1) + iconType;
      item.icon = React.createElement(allIcons[fixIconName] || allIcons[icon]);
    }
    children && children.length > 0 ? (item.children = fixMenuItemIcon(children)) : null;
  });
  return menus;
};

export default fixMenuItemIcon;`

在layout组件中直接调用
`menuDataRender={() => fixMenuItemIcon(menus.menusData)}`

就能解决了

scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js' 。
用的是 Ant Design 的图标库,加上icon- 也不行

你在这个js中搜索一下,有没有一个叫’icon-smile‘的图标名?

我以为这个链接时 antd 的图标库...里面没有smile的图标

这个子菜单的icon好像渲染不出来

@xiangming25
Copy link

从服务器加载 menu 并且使用 icon

这里有 ant-design-pro 的使用示例

@Zeng-Jun-Wei
Copy link

从服务器加载 menu 并且使用 icon

这里有 ant-design-pro 的使用示例

这是写死的icon

@fuyue-sun
Copy link

这么久了还有挖坟的

@yunshangrourou
Copy link

yunshangrourou commented Feb 23, 2022

不改代码,直接在nginx里面加一行rewrite规则即可:
location ~* ^/(.*)/logo\.svg$ { rewrite ^/(.*)/(logo\.svg)$ https://a.com/logo.svg permanent; }

@kddloong
Copy link

动态菜单的渲染 subMenuItemRender 和 menuItemRender 两个渲染API要配合使用。menuItemRender可以参考 #8101 (comment)

@LIFANGTIAN
Copy link

您好 请问解决了吗

@chenjh-8
Copy link

icon 不显示的问题,可以自定义菜单项渲染方法,并引用自定义的图标库。 看到这个问题被关闭,并标记为Feature Request,不知道以后是否有官方解决方案。 我的方案如下:

// MenuItemRender.tsx,`app.tsx`直接引用即可
import { MenuDataItem } from '@ant-design/pro-layout';
import { createFromIconfontCN } from '@ant-design/icons';
import { Link, useIntl } from 'umi';

let IconFont = createFromIconfontCN({
  // 以下是默认值,也可以按需要指定
  // scriptUrl: defaultSettings.iconfontUrl,
});

const getIcon = (
  icon?: string | React.ReactNode,
  iconPrefixes: string = 'icon-',
): React.ReactNode => {
  if (typeof icon === 'string' && icon !== '') {
    // 可加入多种图标类型的兼容写法,此处省略
    if (icon.startsWith(iconPrefixes)) {
      return <IconFont type={icon} className={icon} />;
    }
  }
  return icon;
};

const MenuItem: React.FC<MenuDataItem> = (menuItemProps) => {
  const { formatMessage } = useIntl();
  const { isUrl: isLink, path, icon, locale } = menuItemProps;
  const localeStr = locale as string; // 和 `formatMessage中` 的 `id` 类型不一致,只好断言一下
  const itemContent = (
    <span className="ant-pro-menu-item">
      {getIcon(icon)}
      <span className="ant-pro-menu-item-title">{formatMessage({ id: localeStr })}</span>
    </span>
  );
  return isLink || !path || location.pathname === path ? (
    itemContent
  ) : (
    <Link to={path}>{itemContent}</Link>
  );
};

export default MenuItem;

还是想用 Ant Design 的图标库?拿去吧:https://www.iconfont.cn/collections/detail?cid=9402

image

1 similar comment
@chenjh-8
Copy link

icon 不显示的问题,可以自定义菜单项渲染方法,并引用自定义的图标库。 看到这个问题被关闭,并标记为Feature Request,不知道以后是否有官方解决方案。 我的方案如下:

// MenuItemRender.tsx,`app.tsx`直接引用即可
import { MenuDataItem } from '@ant-design/pro-layout';
import { createFromIconfontCN } from '@ant-design/icons';
import { Link, useIntl } from 'umi';

let IconFont = createFromIconfontCN({
  // 以下是默认值,也可以按需要指定
  // scriptUrl: defaultSettings.iconfontUrl,
});

const getIcon = (
  icon?: string | React.ReactNode,
  iconPrefixes: string = 'icon-',
): React.ReactNode => {
  if (typeof icon === 'string' && icon !== '') {
    // 可加入多种图标类型的兼容写法,此处省略
    if (icon.startsWith(iconPrefixes)) {
      return <IconFont type={icon} className={icon} />;
    }
  }
  return icon;
};

const MenuItem: React.FC<MenuDataItem> = (menuItemProps) => {
  const { formatMessage } = useIntl();
  const { isUrl: isLink, path, icon, locale } = menuItemProps;
  const localeStr = locale as string; // 和 `formatMessage中` 的 `id` 类型不一致,只好断言一下
  const itemContent = (
    <span className="ant-pro-menu-item">
      {getIcon(icon)}
      <span className="ant-pro-menu-item-title">{formatMessage({ id: localeStr })}</span>
    </span>
  );
  return isLink || !path || location.pathname === path ? (
    itemContent
  ) : (
    <Link to={path}>{itemContent}</Link>
  );
};

export default MenuItem;

还是想用 Ant Design 的图标库?拿去吧:https://www.iconfont.cn/collections/detail?cid=9402

image

@1806150981
Copy link

image
image
解决

@Mankvis
Copy link

Mankvis commented Aug 19, 2022

image image 解决

目前尝试了这种写法,导致控制台报出警告:
image

@xjchenhao
Copy link

从服务器加载 menu 并且使用 icon

我也是这个思路

击掌(✧∇✧)╯╰(✧∇✧)̣

@kasnti
Copy link

kasnti commented Aug 7, 2023

根据图标字符串创建图标元素,除了使用上文提到的这个方法:
item.icon = React.createElement(allIcons[fixIconName] || allIcons[icon]);
也可以使用
<Icon component={allIcons['fixIconName']} /> (其中Icon标签来源:import Icon from '@ant-design/icons';
不知道哪个性能好一些?

@coderzym
Copy link

image image 解决

完美解决我的问题,谢谢兄弟

@shg1031
Copy link

shg1031 commented Jan 24, 2024

icon 只能用 dom,access 必须要触发页面的重新渲染才有用

如何重新渲染呢! 贴个示例悄悄呢,大神

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests