[英]Vue-Router language based route prefix
I'm using prerender-spa-plugin
in order to prerender certain pages so I get better SEO from my Vue app. 我正在使用
prerender-spa-plugin
来预呈现某些页面,以便从我的Vue应用程序中获得更好的SEO。
My goal is to transform the way I'm currently using Vue-i18n
, so I can base it on url param /lang
. 我的目标是改变我目前使用
Vue-i18n
,所以我可以将它建立在url param /lang
。 Examples: /en/home
or /nl/home
. 示例:
/en/home
或/nl/home
。 With this, I would be able to pre-render depending on the language. 有了这个,我就可以根据语言进行预渲染。
I created a prefixer function that adds to every parent route the optional param /:lang?
我创建了一个前缀函数,它为每个父路由添加了可选的param
/:lang?
. 。 Here it is:
这里是:
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;
});
In Vue templates, I'm using: 在Vue模板中,我正在使用:
<router-link :to="`/account`">
So I'm trying to manipulate the redirect to the next page according to the lang
param. 所以我试图根据
lang
param操纵重定向到下一页 。
First approach 第一种方法
The most logical one is (inside Router's beforeEach
): 最合乎逻辑的是(在Router的
beforeEach
):
const { lang } = to.params;
const redirectTo = lang ? to.fullPath : `${fullToLang}${to.fullPath}`;
if (from.fullPath !== redirectTo) {
next({ path: redirectTo });
} else {
next();
}
But it enters in an endless loop because from is always the same. 但它进入无限循环,因为从始至终都是一样的。
Second approach 第二种方法
Using Router
's base
property. 使用
Router
的base
属性。
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");
Or better, live: https://codesandbox.io/embed/vue-template-0bwr9 或者更好,直播: https : //codesandbox.io/embed/vue-template-0bwr9
But, I don't understand why it's redirecting to /en/nope
only if the url is not found on the routes (last case). 但是,我不明白为什么只有在路线上找不到网址时才会重定向到
/en/nope
(最后一种情况)。 And more, would I have to create a new Router
instance each time I want to change base
? 而且,每次我想要更改
base
时,我是否必须创建一个新的Router
实例?
Third approach 第三种方法
Wrapper component for router-link
injecting :to
based on this.$route.params.lang
. router-link
注入的包装组件:to
基于this.$route.params.lang
。
This would do it for navigation after the app is loaded but not at the first refresh/initialization. 这将在加载应用程序后进行导航,但不会在第一次刷新/初始化时进行导航。
So, how should I resolve this? 那么,我该如何解决这个问题呢?
~ Solution ~ 〜 解决方案 〜
So yeah, first approach was the correct way to go but I missunderstood how Router behaves with next
and redirects
. 所以是的,第一种方法是正确的方法,但我很想念路由器如何处理
next
和redirects
。 The condition should be checking the to
not the from
. 条件应该是检查
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;
}
I am not entirely sure what you are asking. 我不完全确定你在问什么。 But I assume you want to prefix your navigations with the current language param (../en/..) if they do not already have one?
但是我假设您想要使用当前语言参数(../en/ ..)为您的导航添加前缀,如果它们还没有?
You could resolve this with a beforeEach()
hook and only redirecting if there is no lang
param present. 您可以使用
beforeEach()
钩子解决此问题,并且只有在没有lang
param存在的情况下才会重定向。
const { lang } = to.params
if(!lang) {
next({ path: redirectTo })
}
next()
If that's not what you want please clarify and I'll edit my answer 如果这不是你想要的,请澄清,我会编辑我的答案
/[lang]/...
/[lang]/...
as a note - there are still errors when routing eg /:lang/bar
-> /foo/bar
作为注释 - 在路由例如
/: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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.