解决vuepress-theme-reco中文标签跳转返回404问题

问题

最近在使用vuepress-theme-reco构建属于自己的博客,感兴趣的同学可以自己去官网上构建自己的博客。
在使用这个框架构建博客的时候,发现了一个及其令人头疼的问题——中文标签返回404,具体的表现形式:
中文标签跳转返回404问题

解决办法

很快的啊,我找到了issue,里面的大佬已经给了对应的解释和解决办法。

问题原因:

浏览器对直接输入的中文url做了一次encode导致 匹配不到对应的path,然后就打到了404的路由

大佬给了两条解决办法:

  1. 直接修改node_modules/vue-router/dist/vue-router.esm.js的源码,如果项目仅仅是一个人开发,这种解决办法是十分简单的,对应的代码如下。但是我个人是不太喜欢这种方案,所以是直接采用第二种方案。
// 修改vue-router.esm.js里面的match函数,增加两行代码
function match (
   raw,
   currentRoute,
   redirectedFrom
 ) {

 if(typeof raw ==='string'){
    raw = decode(raw)
 }
 // ...code
}
  1. 可以通过将主题更换到本地,而后修改 vuepress-theme-reco 本地主题的 enhanceApp.js 对应源码解决该问题,这样只要不更新主题就可一次解决。
// enhanceApp.js
import postMixin from '@theme/mixins/posts'
import localMixin from '@theme/mixins/locales'
import { addLinkToHead } from '@theme/helpers/utils'
import { registerCodeThemeCss } from '@theme/helpers/other'

import Router from 'vue-router'

const router = new Router({
 mode: 'history'
})

// 防止相同路由跳转时报错
const VueRouterPush = Router.prototype.push
Router.prototype.push = function push (to) {
 return VueRouterPush.call(this, to).catch(err => err)
}

export default ({
 Vue,
 siteData,
 isServer,
 router
}) => {
 Vue.mixin(postMixin)
 Vue.mixin(localMixin)
 if (!isServer) {
   addLinkToHead('//at.alicdn.com/t/font_1030519_2ciwdtb4x65.css')
   registerCodeThemeCss(siteData.themeConfig.codeTheme)
 }

 router.beforeEach((to, from, next) => {
   // 解决非ASCII文件名的路由, 防止 404
   const decodedPath = decodeURIComponent(to.path)
   if (decodedPath !== to.path) {
     next(Object.assign({}, to, {
       fullPath: decodeURIComponent(to.fullPath),
       path: decodedPath
     }))
   } else {
     next()
   }
 })
}

不建议直接复制粘贴大佬的代码,每个人的版本可能不一致,看自己的enhanceApp.js文件里面缺什么粘贴什么。

新的问题

我直接采用方案2, 但是经过尝试之后发现新的问题,所有带中文的链接跳转不了,报错原因:
溢出报错
这报错原因,我熟啊!栈溢出了。原因也很简单,就是路由重复跳转导致的:
报错原因
将跳转的路径进行decodeURIComponent转换成正常的中文路径,这样路由就可以匹配上了,但是重新跳转之后,浏览器又会将url进行一次encode,也就是说,再次跳转的时候还是会经过 decodePath !== to.path 这个判断条件,一直重复下去,直到栈溢出。

问题的产生原因大致上了解清楚了,解决就很简单了,记录上次格式化的路径就行了,代码如下:

let pre_path = null // 上次格式化的路径
// ……code
router.beforeEach((to, from, next) => {
    // 解决非ASCII文件名的路由, 防止 404
    const decodedPath = decodeURIComponent(to.path)
    if (decodedPath !== to.path && decodedPath!== pre_path) {
      pre_path = decodedPath
      next(Object.assign({}, to, {
        fullPath: decodeURIComponent(to.fullPath),
        path: decodedPath
      }))
    } else {
      next()
    }
 })

但你以为问题就这么解决了?

新新问题

新问题的产生
看来方案二的思路并不适合我这种小白同学,不管怎么改动路由逻辑,终究还是会出现瑕疵。但是在改动代码的时候,我注意到了一点:
代码
大佬改动了一点push的代码逻辑,这段代码倒是提醒了我,方案一不是在match的源码上添加一小段新的源码,而这段代码只是对穿的参数raw进行一个格式化操作,那我为何不用原型链改动match的代码逻辑?

新的解决办法

最终改动的enhanceApp.js代码为:

// enhanceApp.js
/* eslint-disable no-proto */
import postMixin from '@theme/mixins/posts'
import localMixin from '@theme/mixins/locales'
import { addLinkToHead, addScriptToHead } from '@theme/helpers/utils'
import { registerCodeThemeCss, interceptRouterError } from '@theme/helpers/other'
import VueCompositionAPI from '@vue/composition-api'

import Router from 'vue-router'

// 该函数为vue-router.esm.js里面的一段源码,直接拿来使用
function decode (str) {
  try {
    return decodeURIComponent(str)
  } catch (err) {
    if (process.env.NODE_ENV !== 'production') {
      warn(false, ("Error decoding \"" + str + "\". Leaving it intact."));
    }
  }
  return str
}

const VueRouterMatch = Router.prototype.match
Router.prototype.match = function match (raw, currentRoute, redirectedFrom) {
  if (typeof raw === 'string') {
    raw = decode(raw)
  }
  return VueRouterMatch.call(this, raw, currentRoute, redirectedFrom)
}

export default ({
  Vue,
  siteData,
  isServer,
  router
}) => {
  Vue.use(VueCompositionAPI)
  Vue.mixin(postMixin)
  Vue.mixin(localMixin)
  if (!isServer) {
    addLinkToHead('//at.alicdn.com/t/font_1030519_2ciwdtb4x65.css')
    registerCodeThemeCss(siteData.themeConfig.codeTheme)
  }
}

最终解决方案

经过上面的探索,已经把中文标签跳转返回404的问题已经解决了,方案两种:

  1. 改动node_modules/vue-router/dist/vue-router.esm.js源码的match函数,增加两行代码。当然了,这种改动不是我的菜。
  2. 将主题复制粘贴到.vuepress文件中,改名为theme,然后再改动enhanceApp.js代码,代码就在新的解决办法里,自己可以去翻翻。

如果嫌麻烦,可以直接采用方案一;如果想要魔改一下主题,不嫌麻烦的,可以选择方案二;如果像我一样嫌麻烦,又不想用方案一,可以采用方案三。

我们的.vuepress文件里面本来配置了enhanceApp.js文件,这个文件具体是什么情况用,可以点击传送门查看

方案三:

// 直接修改.vuepress文件夹里面的enhanceApp.js文件,增加下面代码,为方便,我就直接复制粘贴我的enhanceApp.js文件了
/**
 * 扩展 VuePress 应用
 */
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

// 新增代码 
import Router from 'vue-router'
function decode (str) {
  try {
    return decodeURIComponent(str)
  } catch (err) {
    if (process.env.NODE_ENV !== 'production') {
      warn(false, ("Error decoding \"" + str + "\". Leaving it intact."));
    }
  }
  return str
}

const VueRouterMatch = Router.prototype.match
Router.prototype.match = function match (raw, currentRoute, redirectedFrom) {
  if (typeof raw === 'string') {
    raw = decode(raw)
  }
  return VueRouterMatch.call(this, raw, currentRoute, redirectedFrom)
}
// end

export default ({
  Vue
}) => {
  // ...做一些其他的应用级别的优化
  Vue.use(Element)
}

原文链接

传送门

参考资料

分类和标签包含中文会导致路由匹配不到,跳转至404页面

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值