antd admin框架设置了base路径后无法正常切换问题

antd admin框架设置了base路径后无法正常切换问题

背景:框架 antd amin,一般情况下,部署在web的根目录(即:http://hostname:port)下面,可正常切换语种,但是,如何部署在web下的某个目录下时,发现:
1、切换语种时,无法正确路由(菜单中的所有链接还是原来的默认语种,而右上角的选择语类无法正确点击)
2、如果直接在url中修改语种时,可正常路由即:
http://localhost:7000/en/dashboard 修改enzh 是能正常访问的

package.json信息如下

"name": "antd-admin",
"version": "5.1.3",
const basePath = '/myCenterWeb'
export default {
  publicPath: `${basePath}/`,
  base: basePath,
  ...
}

问题分析

1、由上面问题2,可知,路由没有问题可正常访问zh或en的。问题出成菜单中生成的路由没有正常加入相应的语种。

代码分析


// 从路径中提取语种,没有,则提返回默认语种
export const langFromPath = pathname => {
  for (const item of languages) {
    if (pathname.startsWith(`/${item}/`)) {
      return item
    }
  }
  return defaultLanguage
}

// 为路径添加语种信息前缀
export function addLangPrefix(pathname) {
  if (!i18n) {
    return pathname
  }
  const prefix = langFromPath(window.location.pathname)
  return `/${prefix}${deLangPrefix(pathname)}`
}

1. 解读 addLangPrefix()

addLangPrefix() 这是为pathname添加语言信息,若已包含语类信息,先剔除,再重新追加语种。看代码:

const url = '/zh/user/12'
const url2 = '/user/12'
console.log(addLangPrefix(url)) // output => /zh/user/12
console.log(addLangPrefix(url2)) // output => /zh/user/12

这个方法也是相当重要,antd amdin左侧的菜单link及面包屑导航的link能正确路由,就是靠这个方法为router地址添加了语种信息的。看下面的代码

<Menu.Item key={item.id}>
   <Navlink to={addLangPrefix(item.route) || '#'}>
     {item.icon && <LegacyIcon type={item.icon} />}
     <span>{item.name}</span>
   </Navlink>
 </Menu.Item>

deLangPrefix() 方法是获取干净在逻辑路由,啥意思呢?就是会把url上标识语言的部分去除,保留定义的逻辑路由,看代码吧:

const url = '/zh/user/12'
console.log(deLangPrefix(url)) // output => /user/12
2.解读 langFromPath()

langFromPath() 这个是从url中提取语言,如果url中没有语言,则返回默认语言,还是看代码吧

const url = '/zh/user/12'
const url2 = '/user/12'
console.log(langFromPath(url)) // output => zh
console.log(langFromPath(url2)) // output => zh

这个方法特别重要,antd amdin的组件之所以可以正常的识别当前语种,就是靠这个方法从url中提取语种信息,然后在layout组件中,统一注入语种信息。

看看layout组件的代码片段:

  render() {
    const { location, children } = this.props
    const { catalogs } = this.state

    let language = langFromPath(location.pathname)   // <- 看,就是这里提取了语种
    // If the language pack is not loaded or is loading, use the default language
    if (!catalogs[language]) language = defaultLanguage

    return (
      <ConfigProvider locale={languages[language]}>
        <I18nProvider language={language} catalogs={catalogs}>
          <BaseLayout>{children}</BaseLayout>
        </I18nProvider>
      </ConfigProvider>
    )
  }

所以,如何语种不能正确设置,那多半是因为不能从url中正确提取语类。

解决办法(不想看分析的,直接看这里)

仅需要修改pages/utils/index.js文件

// 这是新添加的方法
// 获取逻辑路径(指:除去定义的basePath路径前缀)
function getLogicWinLocationPathname() {
  const pathname = window.location.pathname
  if(basePath) {
    return pathname.replace(`${basePath}/`, '/')
  }
  return pathname
}


export function addLangPrefix(pathname) {
  if (!i18n) {
    return pathname
  }
  const winLocationPathname = getLogicWinLocationPathname()  
  const prefix = langFromPath(winLocationPathname)  // 这里是关键 原来是window.location.pathname
  return `/${prefix}${deLangPrefix(pathname)}`
}

export function getLocale() {
  const winLocationPathname = getLogicWinLocationPathname()
  return langFromPath(winLocationPathname) // 这里是关键 原来是window.location.pathname
}

export function setLocale(language) {
  if (getLocale() !== language) {
    const winLocationPathname = getLogicWinLocationPathname()
    moment.locale(language === 'zh' ? 'zh-cn' : language)
    umiRouter.push({
      pathname: `/${language}${deLangPrefix(winLocationPathname)}`, // 这里是关键 原来是window.location.pathname
      search: window.location.search,
    })
  }
}

为什么需要这里改呢? 这是因为:antd admin 原来的代码中,混淆了组件中的pathnamewindow.location.pathname
组件中 通过location属性中获取的pathname是逻辑pathname,不包括.umi.js中设置的base目录,而原代码中,getLocale seLocal addLangPrefix 中却使用了window.location.pathname,这就导致如果项目放在web站点根目录下时这两个值是一样的,没毛病。如果项目放在web站点下的某个目录里,那就会出bug了。

出什么bug呢?从window.location.pathname中提取不到语类,然后又在原路径上添加语种信息,最后导致路由不到的现象。

发布了132 篇原创文章 · 获赞 7 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/youlinhuanyan/article/details/105614457