I'm working on a vue3 project.
The idea is to have a main component composed by a header and 2 view.
When someone click on the h1 button I want to show the relative content under the header but vue-router keep duplicating the entire main component instead of only append the h1 components content under the header
/* main.ts */
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import main from './components/main.vue'
import h1 from './components/h1.vue'
import h2 from './components/h2.vue'
const routes = [
{
path: '/',
component: main,
children: [
{ path: 'h1', component: h1 },
{ path: 'h2', component: h2 },
],
},
]
const router = createRouter({
history: createWebHistory(),
routes,
})
createApp(App).use(router).mount('#app')
<template>
<!-- main.vue -->
<div style="display:flex; flex-direction:column">
<header>Header
<router-link to="h1" >h1</router-link>
<router-link to="h2" >h2</router-link>
</header>
<!-- Here ↓↓↓ I should see only the content from h1 -->
<router-view />
</div>
</template>
<template>
<!-- h1.vue -->
<!-- h2 is the same with: Hi I'm H2 -->
<div>
Hi I'm H1
</div>
</template>
I hope that everything is clear.
To replicate the environment
yarn create vite or npx create vite
choose a vue 3 template then add vue-router as dependency.
So, I've found that for what I need to do vue-router give you the option of using router-view and the component(s) option in route configuration to setup the layout.
Check out named view # router-vue docs for further info.
Related
So using router/index.js I managed to at least get the home page displayed. Now I have moved the code to main.js to simplify it for this question, and not even the home page loads. I only get the vue logo:
main.js:
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
import Home from '#/pages/Home.vue'
import DiscussionPage from '#/pages/DiscussionPage.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/discussion-page/:id',
name: 'DiscussionPage',
component: DiscussionPage,
props: true
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
const forumApp = createApp(App)
forumApp.use(router)
forumApp.mount('#app')
Here's the template from the homepage (Home.vue inside src/pages):
<template>
<div class="home">
<p>This is the home page</p>
<div class="discussions" v-for="discussion in discussions" :key="discussion.id">
<router-link :to="{name: 'DiscussionPage', params: {id: discussion.id}}">
{{ discussion.word}}
</router-link>
</div>
</div>
</template>
There was no issues getting the discussions data before I added vue-router, is why I am not including that part of the code. Also, before I moved the code to main.js the url would change when clicking the router-link for the discussion page, but the page would not load.
I am using vue-router4 and I built the app using the CLI with the default vue3 option.
Any clues of what it is I am doing wrong? I am sure it is anobvious little detail, but I can't find it :-(
Thank you so much :-)
This was really silly, but I guess it is still worth publishing for beginners?
For the vue-router to work, one must add the router-view tag. I guess I could have added it in my home page as Bulent suggested. But I think it makes more sense to add it in App.vue so that affects the whole app.
I have to say that this is not clear at all from the current documentation: https://next.router.vuejs.org/guide/#router-link
So simply adding this on App.vue activated the router, and all works well now :
<template>
<router-view/>
</template>
I'm setting up a brand new Vue 2 project. Due to compatibility issues with one of the libraries I need to use, I can't yet move to Vue 3.
I have a very basic setup at the moment, folder structure something like this:
/
App.vue
main.js
router.js
/pages
AboutUs.vue
Home.vue
If I don't use Vue Router, and just import the AboutUs page into App.vue and call its tag in the template, it displays as expected.
When I instead use the Vue Router to render it in the <router-view /> tag in App.vue, I get the error message:
[Vue warn]: Failed to mount component: template or render function not defined.
I suspect that means I'm doing something wrong in the router but I can't see what.
main.js
import Vue from 'vue'
import App from './App.vue'
import router from 'router.js'
new Vue({
render: h => h(App),
router
}).$mount('#app')
App.vue
<template>
<div id="app">
<router-link to="/">Home</router-link>
<router-link to="/About">About</router-link>
<router-view />
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const About = require('../pages/AboutUs')
const Home = require('../pages/Home')
const routes = [
{
path: '/about',
name: 'About',
component: About
},
{
path: '*',
name: 'Home',
component: Home
}
]
const router = new VueRouter({
linkExactActiveClass: '',
routes
})
export default router
About.vue
<template>
<div>
<h1>About</h1>
</div>
</template>
<script>
export default {
}
</script>
es6 import
Try to use an es6 import instead of require:
import About from '../pages/AboutUs'
import Home from '../pages/Home'
Then your route syntax will work as is. This is because when you use require, you get the whole module rather than the Component export from the module.
-or-
require
Alternatively, if you wanted to continue using require, you would need the following syntax, using the default property of the module:
const About = require('../pages/AboutUs')
const Home = require('../pages/Home')
const routes = [
{
path: '/about',
name: 'About',
component: About.default
},
{
path: '*',
name: 'Home',
component: Home.default
}
]
I have just started learning Vue. I actually became confused with the Vue router part. It's a very simple question. I tried looking for many docs and tuts but didn't find anything that I was looking for. It might be my fault on not implementing them correctly which I can understand as a beginner but still got stuck. Let me explain what I am trying to obtain and what I did so far.
This is my Home.vue file and I want user to see this page by default on / path.
<template>
<div>
<MainNavigation />
<LandingSection />
<Services />
<WhyKontext />
<SignupTrial />
<Footer />
</div>
</template>
This is my code for App.vue
<template>
<div>
<Home />
</div>
</template>
<script>
import Home from "./views/landing/Home";
export default {
name: "App",
components: {
Home,
},
};
</script>
This is my router.js
import Vue from "vue";
import VueRouter from "vue-router";
import LoginRegister from "./views/account/LoginRegister";
import App from "./App";
Vue.use(VueRouter);
export default new VueRouter({
mode: "history",
routes: [
{
path: "/",
component: App,
},
{
path: "/account",
component: LoginRegister,
},
],
});
On MainNavigation.vue there is this block of code
<router-link to="/account" class="bg-color text-white">TRY CONTEXT </router-link>
What I am trying is: If a user clicks on TRY KONTEXT button, I want them to go to Signup/Login page named as LoginRegister.vue.
I tried by putting <router-view></router-view> on MainNavigation but LoginRegister page comes attached with the rest of the Home components. When I am on http://localhost:8080/ then I get complete Home. When I click on TRY KONTEXT button It takes me to http://localhost:8080/account but I still can see All the Home Components along with LoginRegister. I am trying to make MainNavigation and Footer at all pages and Just change the content at middle according to the route. In this case, I actually wanted to see MainNavigation, LoginRegister and Footer. I know it's a silly question. Please help me.
Try putting your router-view in your App.vue, with the basic layout in it, such as header/footer/side_bar. Now, your App.vue should contain something like this:
<template>
<div class="container">
<AppHeader></AppHeader>
<router-view/>
<AppFooter></AppFooter>
</div>
</template>
Then move your Home.vue to a separate file, so that it doesn't contain header and footer which you already included in your layout:
<template>
<div class="container">
<carousel></carousel>
<image-grid></image-grid>
</div>
</template>
Now, in your router.js, specify the routes, almost like this:
import Home from './path/to/home.vue'
routes = [
{
path: '/',
name: 'home',
component: Home
}
]
Try editing your App.vue component template like this:
<template>
<div>
<router-view/>
</div>
</template>
The logic behind this is that the app is showing the current selection of your router.
I have a really simple minimal example page with vue-router which is only partially working.
app.js
import 'babel-polyfill';
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './app.vue';
import router from './router'
new Vue({
router,
render: h => h(App)
}).$mount('#app')
app.vue
<template>
<div class="container">
<div id="nav">
<router-link to="/">Page 1</router-link>|
<router-link to="/page2">Page 2</router-link>
<router-link to="/sretbs">No page</router-link>
</div>
<div style="border:5px solid green">
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {};
</script>
router.js
import Vue from 'vue'
import Router from 'vue-router'
import Page1 from './page1.vue';
import Page2 from './page2.vue';
import ErrorPage from './error.vue';
Vue.use(Router)
export default new Router({
routes: [
{ path: '/page1', name: 'page1', component: Page1 },
{ path: '/page2', name: 'page2', component: Page2 },
{ path: '*', component: ErrorPage }
],
redirect: {
"/": "page1"
}
})
The <router-view> appear to work on first page load. It shows the component I expect for whatever route is currently in the url (e.g. localhost/test#/page2), or if I explicitly route.push before binding Vue to #app it also shows the expected component.
Navigating to other routes doesn't appear to fully work, or at least it's not rendering the new route. When I add debug output to the page components like so:
<template>
<div class="container">
<h2>this is page 2</h2>
<buttons></buttons>
</div>
</template>
<script>
export default {
beforeRouteEnter: function(to, from, next) {
console.log(`Entering page 2:`);
next();
},
beforeRouteLeave: function(to, from, next) {
console.log(`Leaving page 2`);
next();
},
beforeRouteUpdate: function() {
console.log(`Before route update`);
}
};
</script>
it is picking up the routeenter/leave events. I can seemingly navigate back and forth between routes, but you don't see the result until a page reload
I can't recreate the problem in a jsfiddle, and I've scrapped everything and started again but am getting the same result. I can't see anything I'm doing wrong from looking at the Vue Router documentation. Any idea what I'm missing here?
In this instance the answer was painfully simple. There was another Vue instance on the page elsewhere. Even though my understanding is separate Vue instances bound to different container elements should be able to exist in harmony, in this instance it wasn't. It was also what was breaking the Vue dev tools, showing a Vuex instance for example but not showing any of the loaded components and giving a Cannot read property '__VUE_DEVTOOLS_UID__' of undefined error in the Vue Dev Tools errors.
I have 2 router links that link to the same page (definition page) but has different ids, in my definition page I have an if else loop that checks the id and then posts the apropriate definition for that id.my problem is that my loop can't properly read my id and goes straight to my else statment, this is the closest that I've gotten it to work.
My 2 router-links in page 1
<router-link :to="{ path: '/Pulse/Definition',id:'Alignment'}" v-bind:tooltip="Alignment" append><a >Read more ></a></router-link>
<router-link :to="{ path: '/Pulse/Definition'}" id="Trust" append><a >Read more ></a></router-link>
My definition page
<template>
<div class="PulseDefinition page row">
<h2 v-if=" id=='Alignment'">hello world {{id}}</h2>
<h2 v-else-if=" id=='Trust'">hello world {{id}}</h2>
<h2 v-else>Sorry try again</h2>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.PulseDefinition{
margin-top:2.5rem;
margin-left:3rem;
background-color: aquamarine;
width:50rem;
height:50rem;
}
</style>
Router
import Vue from 'vue';
import Router from 'vue-router';
import Community from '../components/PulseCommunity';
import Home from '../components/Home';
import Definition from '../components/Definition.vue';
Vue.use(Router)
export default new Router({
routes:[
{
path:'Tuba',
name:'Tuba',
component: Default
},
{
path:'/Pulse',
name:'Pulse',
component:PulseNav,
children:[{
path:'/Pulse/Overview',
name:'Overview',
component:Overview
},
{
path:'/Pulse/Personal',
name:'Personal',
component:Personal
},
{
path:'/Pulse/Community',
name:'Community',
component:Community
},
{
path:'/Pulse/Definition/:id',
name:'Pulse Definition',
component:Definition
}
]
},
{
path:'/Coaching',
name:'Coaching',
component:Coaching
},
{
path:'/Comunication',
name:'Comunication',
component:Comunication
},
{
path:'/Home',
name:'Home',
component:Home
},
]
})
Normally when your using the router inside of a Vue application you'll want to use route parameters, check out the dynamic routing link here.
Using the same example:
const router = new VueRouter({
routes: [
// dynamic segments start with a colon
{ path: '/user/:id', component: User }
]
})
Here in our router whenever we navigate to a url where /user/ is present providing we then add something after we can match the /:id section of it. Then inside of our component we are able to query the parameters for the ID that was sent in our url:
console.log(this.$route.query.id)
Using this we could then save that value into our component or we could build reactivity around this.$route.query.
In your case you'd only need to append to the string that you pass into that router link by simply using your data / methods or if you require further rules you could use a computed method. This might become or something simmilar:
<router-link :to="{ path: '/Pulse/Definition'+ this.alignmentType}" v-bind:tooltip="Alignment" append><a >Read more ></a></router-link>
i found a solution thx to the help of li x and a senior coworker of mine,here is the awnser.
my working router-link in page 1
<router-link :to="{ path: '/Pulse/Definition/'+'Alignment'}" v-bind:tooltip="Alignment" append><a >Read more ></a></router-link>
im adding the id(Alignment) to my url with[:to="{ path: '/Pulse/Definition/'+'Alignment'}"]
my definition page
<template>
<div class="PulseDefinition page row">
<h2 v-if=" this.$route.params.id=='Alignment'">hello world {{this.$route.params.id}}</h2>
<h2 v-else-if=" this.$route.params.id=='Trust'">hello world {{this.$route.params.id}}</h2>
<h2 v-else-if=" this.$route.params.id=='undefined'">Sorry try again {{this.$route.params.id}}</h2>
<h2 v-else>XXXSorry try againXXX{{this.$route.params.id}}</h2>
<!-- {{console.log("hi")}} -->
</div>
</template>
<script>
// console.log(this.$route.query.id);
export default {
}
</script>
im using [this.$route.params.id] to retrieve my id, and my router page stayed the same.
thank you all for the great help ;)