我们正在基于Vue和Nuxt构建一个巨大的网站,具有超过25种不同的页面类型,这些页面类型无法与Vue Router随附的标准/:id或/ overview /:slug逻辑匹配。
由于不能选择塞子匹配,因此我们正在考虑以下解决方案:
topicPage
topicPage
与nuxt页面WpTopicPage
WpTopicPage
设置为Vue Router通配符实例中的组件这类似于代码中的以下内容:
export function createRouter() {
return new Router({
mode: 'history',
routes: [
// 1. User visits page "/this-is-a-topic-page"
{
name: 'wildcard',
path: '*',
component: *, // this should be dynamic
beforeEnter: (to, from, next) => {
// 2. Server calls API that returns the pageType `topicPage`
this.$axios.get(`/call-to-the-api?slug=${to.params.slug}`)
.then((res) => {
// 3. `topicPage` relates to the nuxt page `WpTopicPage`
if(res.data.pageType === 'topicPage') {
// 4. Set `WpTopicPage` as our Page component
return WpTopicPage;
}
})
},
},
],
});
}
以上内容显然无效。是否可以在beforeEnter函数中动态设置路由内的component
?
答案 0 :(得分:2)
前段时间我一直在为类似的任务而苦苦挣扎。我还需要一个完全动态的路由器,但我的应用程序初始化顺序有点不同。
new Vue({...})
),我没有路由,也没有相关组件。很酷的是,可以在任何时间点映射和重新映射路由器。
我认为即使使用您的初始化序列,您也可以使用我的实现。
这是我的router.js
import Vue from 'vue';
import Router from 'vue-router';
Vue.use(Router);
const createRouter = () =>
new Router({
mode: 'history',
linkActiveClass: 'active',
base: __dirname,
routes: []
});
const router = createRouter();
export function resetRouter() {
const newRouter = createRouter();
router.matcher = newRouter.matcher;
}
export default router;
注意有 resetRouter
函数。我认为它的作用是不言自明的。
一旦您的应用知道需要映射/使用什么样的路由和组件,您就可以创建路由集合并映射它们。像这样:
import { default as router, resetRouter } from '@/router';
// ...
let routes = [];
// some magic to fill the routes array
// I.e. items coming from API
items.forEach(item => {
if (item.view) {
const component = () => import(`@/views/${item.view}.vue`);
const route = {
name: null, // prevent duplicate named routes warning
path: item.path,
component,
meta: {
title: item.title
}
};
routes.push(route);
}
});
resetRouter();
router.addRoutes(routes);
答案 1 :(得分:0)
有可能做。我创建了一个codepen供您测试:
这里是:
Vue.use(VueRouter);
let A = {
mounted() {
console.log('Mouted component A');
},
};
let B = {
mounted() {
console.log('Mouted component B');
},
};
let C = {
mounted() {
console.log('Mouted component C');
},
};
const router = new VueRouter({
mode: "hash",
routes: [
{
path: '*',
beforeEnter(to, from, next) {
let components = {
default: [A, B, C][Math.floor(Math.random() * 100) % 3],
};
to.matched[0].components = components;
next();
}
},
]
});
app = new Vue({
router,
el: '#app',
components: { A, B, C }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.2/vue-router.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<router-link :to="'/' + Math.random()">anything</router-link>
<router-view></router-view>
</div>
这是输出:
您可以在控制台日志中看到-每次更改时,我们都会随机加载和安装组件。
答案 2 :(得分:0)
这是一个解决方案。
Home.vue
和NotFound.vue
的路由是手动设置的*.vue
目录中的其他视图(views
)动态创建路由.vue
文件的小写字母,除了Home.vue
设置为/
之外。例如)FileName.vue
的路径为/filename
项目结构
app
|__router
|__index.js
|__views
|__Home.vue
|__NotFound.vue
|__*.vue
index.js
import Vue from "vue";
import VueRouter from "vue-router";
// list of files in the `views` directory
const views = require.context(
`../views`,
true,
/^.*\.vue$/
)
Vue.use(VueRouter);
// routes
const routes = [{
path: "/",
name: "Home",
component: import("../views/Home.vue")
}]
// dynamically add all routes in views directory
for (var i = 0; i < views.keys().length; i++) {
// skip home and notfound since it is defined above
if (
views.keys()[i].slice(2, -4) !== 'Home' &&
views.keys()[i].slice(2, -4) !== 'NotFound'
) {
// file path for the route
let filePath = `views/${views.keys()[i].slice(2, -4)}.vue`
// add routes
routes.push({
path: views.keys()[i].slice(1, -4).toLowerCase(),
name: views.keys()[i].slice(2, -4),
component: () =>
import("../" + filePath)
})
}
}
// directs any undefined route to not found
routes.push({
path: "*",
name: "NotFound",
component: () => import("../views/NotFound.vue")
})
const router = new VueRouter({
routes: routes
});
export default router
答案 3 :(得分:0)
@AndrewShmig 和@fjemi 的两个回答都是很好的想法,唯一的问题是他们不符合 Vue Router 的预期设计。似乎 Vue 开发人员希望“to”是静态的,除了元字段,组件中的函数应该是一个 promise,在第一次使用路由后会被缓存。
我认为同意文档的唯一方法是使用 BeforeEnter 钩子将新组件推送到“/*”路由中,标记元字段,然后返回重定向。这将导致重新进入钩子,这次使用正确的组件。不断用每个条目替换路由有点令人不安,但希望它不会导致内存泄漏。由于我们正在替换一个预先存在的路由,我们可以期望它在路由器的一侧进行优化 - 但我没有检查 -。
答案 4 :(得分:0)
我们当前的解决方案没有违反守卫中“只读”to
和from
参数的要求,但是它需要访问路由的内部来安装代理,所以推荐的方法“替换路由并重定向到替换的路由”不太标准。然而,如果您不想每次都重写路由树,它会很有用。
首先我们安装一个守卫来将新路由保存在一个全局变量中。对于路由器的上下文来说足够全局。
router.beforeEach( (to,from) => {nuevaRuta = to })
我们保存了 to
,但它仍然是“只读的”。看看如何:我们使用代理定义组件和道具:
var nuevaRuta = 'None'
const proxyComponentes = {
get: function (target, prop, receiver) {
return FriendlyIframe;
},
ownKeys: (oTarget, sKey) => {
if (nuevaRuta == 'None' || typeof nuevaRuta.params.panes == 'undefined')
return Reflect.ownKeys(oTarget,sKey)
else {
return nuevaRuta.params.panes
}
},
getOwnPropertyDescriptor(target, prop) { // called for every property
return {
enumerable: true , configurable: true /* ...other flags, probable "value:..." */
};
}
};
const proxyPropiedades = {
get: function (target, prop, receiver) {
console.log(prop)
if (prop.startsWith('user_')){
var id = prop.replace('user_','')
return {src: `/u/${id}?noheader=true`}
}else{
return {src: `/p/${window.PRID}/${prop}?noheader=true`}
}
}};
var myComponents = {};
var myProps= {};
我们在构建路由匹配时安装它们。更准确地说,对于版本 4 的路由器,可以在路由定义期间安装组件的代理:
routes:[
{
name: "generica",
path: '/:panes+',
components: new Proxy ( myComponents, proxyComponentes),
props: false
但是 props 是通过规范化“缓存”的,所以我们需要在之后安装它。在我看来,这是最令人不安的细节
router.getRoutes().find( (e) => e.name=="generica").props = new Proxy (myProps, proxyPropiedades)
当然,如果路由器在组件处理中实现缓存和进一步优化,该方法可能会停止工作。如果您想要一个长期安全的解决方案,请继续更新和重定向。