【问题标题】:Vue-Router language based route prefix基于 Vue-Router 语言的路由前缀
【发布时间】:2019-12-19 03:33:42
【问题描述】:

我使用prerender-spa-plugin 来预渲染某些页面,以便从我的 Vue 应用程序中获得更好的 SEO。

我的目标是改变我目前使用Vue-i18n 的方式,所以我可以基于url 参数/lang。示例:/en/home/nl/home。有了这个,我就可以根据语言进行预渲染。

我创建了一个前缀函数,它为每个父路由添加可选参数/:lang?。这里是:

const withPrefix = (prefix: string, routes: RouteConfig[]): RouteConfig[] => routes.map((route): RouteConfig => {
  // Avoiding mutations
  const clonedRoute = { ...route };
  // Every route except for '/'
  if (clonedRoute.path !== '/') {
    clonedRoute.path = prefix + clonedRoute.path;
  }
  return clonedRoute;
});

在 Vue 模板中,我使用的是:

<router-link :to="`/account`">

所以我正在尝试根据lang 参数将 redirect 操作到 next 页面。

第一种方法

最合乎逻辑的是(在Router的beforeEach里面):

const { lang } = to.params;
const redirectTo = lang ? to.fullPath : `${fullToLang}${to.fullPath}`;
if (from.fullPath !== redirectTo) {
  next({ path: redirectTo });
} else {
  next();
}

但它进入了一个无限循环,因为 from 总是相同的。

第二种方法

使用Routerbase 属性。

import Vue from "vue";
import App from "./App.vue";
import VueRouter from "vue-router";
import HelloWorld from "./components/HelloWorld";
import Test from "./components/Test";

Vue.config.productionTip = false;

Vue.use(VueRouter);

const router = new VueRouter({
  mode: "history",
  base: "/en",
  routes: [
    {
      path: ":lang?/",
      component: HelloWorld,
      beforeEnter: (to, from, next) => {
        console.log(1);
        next();
      }
    },
    {
      path: "/:lang?/nope",
      component: Test,
      beforeEnter: (to, from, next) => {
        console.log(2);
        next();
      }
    },
    {
      path: "/:lang?/*",
      beforeEnter: (to, from, next) => {
        console.log(to);
        next("/nope");
      }
    }
  ]
});

new Vue({
  render: h => h(App),
  router
}).$mount("#app");

或者更好,生活: https://codesandbox.io/embed/vue-template-0bwr9

但是,我不明白为什么它重定向/en/nope,只有在路由上找不到url(最后一种情况)。而且,每次我想更改base 时,我是否必须创建一个新的Router 实例?

第三种方法

基于this.$route.params.lang 注入:torouter-link 包装器组件。

这将在应用加载后进行导航,但不是在第一次刷新/初始化时。

那么,我应该如何解决这个问题?

~ 解决方案 ~

所以,是的,第一种方法是正确的方法,但我误解了路由器与 nextredirects 的行为方式。条件应该是检查to 而不是from

const redirectTo = lang ? to.fullPath : `${fullToLang}${to.fullPath}`;
if (to.fullPath !== redirectTo) {
  // Change language at i18n
  loadLanguageAsync(toLang as Language);

  next({ path: redirectTo });

  return;
}

【问题讨论】:

    标签: vue.js vuejs2 vue-router vue-i18n


    【解决方案1】:

    我不完全确定你在问什么。但我假设你想用当前语言参数 (../en/..) 为导航添加前缀,如果它们还没有的话?

    您可以使用 beforeEach() 挂钩解决此问题,并且仅在不存在 lang 参数时重定向。

    const { lang } = to.params
    if(!lang) {
      next({ path: redirectTo })
    }
    next()
    

    如果这不是你想要的,请澄清,我会编辑我的答案

    【讨论】:

    • 我太固执地认为条件必须与from而不是to有关。我不太了解路由器在重定向时的行为方式,我认为在第一个 next 之后会发生变化。
    【解决方案2】:

    像这样?假设是新路径开始/[lang]/...

    作为说明 - 路由时仍然存在错误,例如/:lang/bar -> /foo/bar

    Vue.lang = 'en'
    function beforeEnter(to, from, next){
    
      if ((new RegExp(`^/${Vue.lang}$`))
      .test(to.path) 
      || 
      (new RegExp(`^/${Vue.lang}/`))
      .test(to.path))
      {
        next();
      } else {
        
        next({path: `/${Vue.lang}${to.path}`})
      }
    };
    Vue.mixin({
      beforeRouteEnter: beforeEnter
    })
    const Foo = { template: '<div>foo - {{$route.path}}</div>' }
    const Bar = { template: '<div>bar - {{$route.path}}</div>' }
    const Root = { template: '<div>Root - {{$route.path}}</div>' }
    const Invalid = { template: '<div>404</div>' }
    
    const routes = [
      
      { path: '/:lang/foo', component: Foo },
      { path: '/:lang/bar', component: Bar },
      { path: '/:lang/*', component: Invalid },
      { path: '/:lang', name: 'Home', component: Root },
      // some weird issue that prevents beforeRouteEnter ? so redirect, but else next is needed
      { path: '/', redirect: to => `/${Vue.lang}`}
    ]
    
    const router = new VueRouter({
      routes
    })
    
    new Vue({
      data(){
        return {
          pLang: Vue.lang,
        }
      },
      computed: {
        lang: {
          get(){
            return this.pLang
          },
          set(val){
            Vue.lang = val
            this.pLang = val
          }
        }
      },
      router,
    }).$mount('#app');
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    
    <div id="app">
      <h1>Hello App!</h1>
      <p>
         {{lang}}
        <select v-model="lang">
          <option value="en">en</option>
          <option value="cn">cn</option>
        </select>
        <!-- use router-link component for navigation. -->
        <!-- specify the link by passing the `to` prop. -->
        <!-- `<router-link>` will be rendered as an `<a>` tag by default -->
        
        <router-link to="/">Root</router-link>
        <router-link to="/foo">Go to Foo</router-link>
        <router-link to="/bar">Go to Bar</router-link>
        <router-link to="/foo/bar">Go to Foo/Bar - not defined</router-link>
      </p>
      <!-- route outlet -->
      <!-- component matched by the route will render here -->
      <router-view></router-view>
    </div>

    【讨论】:

      猜你喜欢
      • 2021-11-11
      • 2011-01-03
      • 2016-07-01
      • 2019-10-20
      • 2020-04-11
      • 2016-09-20
      • 1970-01-01
      • 2019-03-15
      • 2018-02-09
      相关资源
      最近更新 更多