We are building an enormous website based on Vue and Nuxt with over 25 different page types that cannot be matched with standard /:id or /overview/:slug logic that comes out of the box with Vue Router.
As slug-matching isn't an option, we are thinking about the following solution:
topicPage
topicPage
relates to the nuxt page WpTopicPage
WpTopicPage
as our component within our wildcard instance of Vue RouterThis looks like the following in code:
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;
}
})
},
},
],
});
}
The above obviously doesn't work. Is there a way to set the component
within a route dynamically in the beforeEnter function?
It's possible to do. I have created a codepen for you to test:
Here it is:
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>
This is the output:
As you can see in the console logs - each time something changes we get random component loaded and mounted.
I've struggled some time ago with a similar task. I also needed a fully dynamic router but my app initialising sequence was a bit different.
new Vue({...})
), I have no routes and no related components.The cool thing is, it is possible to map and re-map the router at any point in time.
I think you can make use of my implementation even with your initialisation sequence.
So here is my 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;
Take note that there is the resetRouter
function. I think it is self-explanatory what it does.
As soon as your app knows what kind of routes and components need to be mapped/used, you can create the route collection and map them. Like so:
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With