vue components registration and routes - vue.js

I want to use routing in my vue project, but don't register many components globally, I am having trouble here.
My project uses vue-cli and vue-router
My project idea is to register these subcomponents only in the parent component that uses the corresponding subcomponent, but I want to use routing to control the presentation of these components.
My code is as follows
Main.js
import Vue from "vue";
import App from "./App";
import VueRouter from 'vue-router'
import test from "./components/test.vue"
Vue.use(VueRouter)
Vue.config.productionTip = false;
const routes = [
{
path: '/test', component: test,
}
]
const router = new VueRouter({routes: routes});
new Vue({
router,
render: h => h(App),
}).$mount('#app')
App.vue
<template>
<div>
<main-layout>
<router-view></router-view>
</main-layout>
</div>
</template>
<script>
import MainLayout from "./components/MainLayout.vue"
import test from "./components/test.vue"
export default {
components: {
"main-layout": MainLayout,
"test": test
},
name : "app",
data(){
return {
collapsed: false,
}
},
}
</script>
Just like the code above, I have to register every component that needs to be managed by routing in main.js and app.vue. These are cumbersome and the code is not beautiful. Is there any way or plugin to solve this problem?

You can move all the routing code to a different folder (possibly named router).
Inside the folder you can have a file called index.js that builds the router and move individual routing components to different files.
Each router component should only return router information and not a router object.
You'll still need to import individual vue components, but they'll be scattered across multiple files. This should make things tidier.
In your main.js will need to import the router, something similar to this
import router from './router'
....
Vue.use({
router
})
This is a possible folder structure for your router:
This is part of router/index.js that shows how to use routes defined in other files
import Vue from 'vue'
import Router from 'vue-router'
import API from '#/api'
import DashboardRoutes from './dashboard'
import CustomerRoutes from './customer'
import MaintenanceRoutes from './maintenance'
import DashboardStudioRoutes from './studio'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/api',
name: 'Api',
component: Api
},
DashboardStudioRoutes,
DashboardRoutes,
CustomerRoutes,
MaintenanceRoutes,
{
path: '*',
name: '404',
component: NotFound
},
],
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
})

Related

Why do I see a previous route component when using vue router 3 navigation?

Let's say we have 3 routes and for the sake of making it simple, they're just referred to as 1, 2, and 3.
When I navigate to route 1 -> route 2 -> route 3 -> route 1, route 2 shows between the navigation from route 3 -> route 1. I can't for the life of me figure out why that's happening.
Routes file is like:
import Vue from 'vue';
import VueRouter from 'vue-router';
import Route1 from '../views/Route1';
import Route2 from '../views/Route2';
import Route3 from '../views/Route3';
Vue.use(VueRouter);
const routes = [
{
path: '/route1',
name: 'Route1',
component: Route1
},
{
path: '/route2',
name: 'Route2',
component: Route2
},
{
path: '/route3',
name: 'Route3',
component: Route3
}
];
const router = new VueRouter({
mode: 'history',
base: '/',
query: {
t: window.token
},
routes
});
export default router;
main.js
import 'sass/main.scss';
import moment from 'moment';
import Vue from 'vue';
import { mapActions, mapState } from 'vuex';
import App from './App.vue';
import api from './plugins/api.js';
import vuetify from './plugins/vuetify';
import router from './router';
import store from './store';
Vue.prototype.$moment = moment;
Vue.use(api);
Vue.config.productionTip = false;
new Vue({
computed: {
...mapState
},
methods: {
...mapActions
},
router,
store,
vuetify,
watch: {
$route() {
try {
// ... some action(s) on route change - removed here
} catch (error) {
// ... error handling removed
}
}
},
render: h => h(App)
}).$mount('#app');
App.vue
<template>
<v-app>
<!-- header/app bar removed here -->
<v-main>
<v-progress-linear
v-if="loading"
color="primary lighten-2"
height="2"
indeterminate
/>
<router-view v-else />
</v-main>
<!-- footer removed here -->
</v-app>
</template>
Kind of dumb, but I'll put it out there anyway. My components were rendering dynamic components that were in the store... upon navigating to a new route I just had to clear the stored component array while the new component array was fetched from the API. So when going back to another route it was first seeing a flash of the old array of dynamic componets.

Vue.js two different main Layouts

I am using vue.js version 2.5.13 installed with the vue-cli using the webpack-template.
Now I would like to use the generated App.vue-template for all my public pages and another template AdminApp.vue for all my admin-routes.
My router/index.js is like this:
import Vue from 'vue'
import Router from 'vue-router'
import LandingPage from '#/components/LandingPage'
import AdminDashboard from '#/components/admin/AdminDashboard'
Vue.use(Router);
export default new Router({
routes: [
{
path: '/',
name: 'LandingPage',
component: LandingPage
},{
path: '/admin/dashboard ',
name: 'AdminDashboard',
component: AdminDashboard
}
}
My main.js is like this:
import Vue from 'vue';
import App from './App.vue';
import AdminApp from './AdminApp.vue';
import router from './router';
if (window.location.href.includes('/admin/')) {
new Vue({
el: '#app',
router,
components: {AdminApp},
template: '<AdminApp/>'
});
} else {
new Vue({
el: '#app',
router,
components: {App},
template: '<App/>'
});
}
Now if I go to localhost:8080/#/ and then via url to localhost:8080/#/admin/dashboard the admin-panel does not use the AdminApp.vue-Template but the App.vue-Template. If I refresh this page, it works.
Do you know why? Are there some best practices for using two or more different templates for different routes?
In Brief:
You should make your layouts.For example layout1 & layout2.
Then you should define them as global component in your main.js and finally use them with v-if in your app.vue depends on your condition.
With Detail:
first in router/index.js:
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/auth/login',
name: 'login',
meta:{layout:"auth"},
component: Login
},
which first route will render with admin layout and second one render with Auth layout for example.
Now in main.js we will define layouts as component:
import Admin from './Layouts/Admin.vue'
import Auth from './Layouts/Auth.vue'
Vue.component('Admin',Admin);
Vue.component('Auth',Auth);
Then in App.vue we check meta datas that passed from routes to detect which layout needs:
<Auth v-if="this.$route.meta.layout==='auth'"/>
<Admin v-if="this.$route.meta.layout==null"/>
Ok.All thins done!
Now we have two layout.

Vue router components evaluated on import

I have an application like
import Vue from 'vue';
import VueRouter from 'vue-router';
import router from './routes.es6';
Vue.use(VueRouter);
new Vue({
router,
}).$mount('#app');
routes.es6 contains my router module:
import VueRouter from 'vue-router';
import Index from './pages/index.vue';
const routes = [
{
path: '/',
name: 'index',
component: Index,
},
...
];
export default new VueRouter({
routes,
});
This works but has one major drawback. Let's assume my index component is defined as follows
<template>
...
</template>
<script>
require(...)
export default {
...
};
</script>
Now all require and import statements are evaluated once the components are imported in the routes.es6 file and they are injected in the main app even though they should be scoped to the specific route.
How to overcome this?
It is called - LAZY LOADING
It is explained well in Vue-Router docs.
https://router.vuejs.org/en/advanced/lazy-loading.html

How to use Vue Router in Vue 2

I'm learning Vue, and started of with the webpack template. The first thing I'm trying to do is to add support for Vue Router, but I've spent several hours on it now without being able to render a single route (I always end up with a blank page). Frustrating!
I simply want to have a single .vue file, acting as the layout file, into which different .vue files, acting as "pages", are rendered into. Can someone tell me how to do this, please? Here's my latest failed attempt:
main.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
import Home from './components/Home'
import About from './components/About'
Vue.use(VueRouter)
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
const app = new Vue({
router: new VueRouter({
routes
}),
component: App
}).$mount('#app')
App.vue (the layout file)
<template>
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/">Go to Foo</router-link>
<router-link to="/about">Go to Bar</router-link>
</p>
<router-view></router-view>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
components/About.vue (almost identical to components/Home.vue)
<template>
<div>
<h1>About</h1>
<p>This is the about page!</p>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
I finally got it to work. The main.js file should be written like this:
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
import Home from './pages/Home'
import About from './pages/About'
Vue.use(VueRouter)
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router,
template: '<App />',
components: {
App
}
}).$mount('#app')
I hope this saves hours of trouble for someone else.
EDIT
The following:
const app = new Vue({
router,
template: '<App />',
components: {
App
}
}).$mount('#app')
can preferably be replaced with:
const app = new Vue({
router,
render: function(createElement){
return createElement(App)
}
}).$mount('#app')
I found out how to get main.js to call the index.js file in folder router and work with the routes defined there:
I had created my app via the VUE UI (with VUE 3.1 and CLI/3)
In the VUE UI there is an option to add plugins. I chose the router plugin (route) and it asked if I want to install a new route or install the framework. (You first need to install the framework...)
It then changed my main.js file to have the following: (the additions are marked with comments)
import Vue from 'vue'
import './plugins/axios'
import App from './App.vue'
import router from './router' // added by router plugin
Vue.config.productionTip = false
new Vue({
router, // added by router plugin
render: h => h(App)
}).$mount('#app')
It also added a new folder router and in it index.js with the code
import Vue from 'vue'
import VueRouter from 'vue-router'
// import Hello from '#/components/HelloWorld' // #pashute: I added this later...
Vue.use(VueRouter)
const routes = [
// {
// path: '/',
// name: 'Hello',
// component: Hello
// }
]
// eslint-disable-next-line no-new
const router = new VueRouter({
routes
})
export default router
It also installed the latest router package and added a link in the HelloWorld component to the router documentation.
By the way, notice the extra name: in the route definitions.

vue 2.0 and vue-router 2.0 build SPA, router-view did not update

Build A Single page app with vue 2 and vue-router 2 and vuex 2, but do not update
/src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import { sync } from 'vuex-router-sync'
sync(store, router)
new Vue({
router,
store,
...App
}).$mount('#app')
/src/router/index.js
import Vue from 'vue'
import routes from './routes'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const router = new VueRouter({
mode: 'history',
routes
})
export default router
/src/router/routes.js
import loader from './loader'
const routes = [
{ path: '/index', name: 'index', component: (r) => require(['./../views/index.vue'], r) }
]
export default routes
/src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {}
})
export default store
/src/view/index.vue
<template>
<div>
<h1>Hello index</h1>
</div>
</template>
<script>
import loader from './../../../router/loader'
export default {
name: 'index',
created () {
console.log('This is index')
}
}
</script>
/src/App.vue
<template>
<div id="app">
<router-link :to="'index'">index</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'app',
mounted () {
console.log('Hello App')
}
}
</script>
I do not know what's wrong with the code, the <router-view> do not update when I change the route.
I think your app is not properly initialized yet. You are starting your app as follows:
new Vue({
router,
store,
...App
}).$mount('#app')
You have the spread operator ...App, which is not necessary - it is used to convert array items to function args, and not correct in this context. Instead you should use the render function as provided in webpack template :
/* eslint-disable-line no-new */
new Vue({
el: "#app",
store,
router,
render: h => h(App)
})
Also you have attempted to import loader in routes and index, which is not necessary if you are using vue-cli.
Maybe you can start with the webpack template as base and slowly add functionality one step at a time: start with route definitions and your route components, ensure that everything works, and finally add vuex.
$mount('#app') is fine, I think the problem is your routes.js
Try this instead:
import Index from './../views/index.vue'
const routes = [
{ path: '/index', name: 'index', component: Index }
]
And here is a working webpack template which is already configured vue-router and vuex properly, you can initialize this template via vue-cli, for your reference: https://github.com/CodinCat/vue-webpack-plus