I am using Vue after a long pause so sorry in advance for rather silly question.
I have a navigation component which is nested in layout component. The problem is that it is not visible on the page and in DevTools but I can see it in my Vue Chrome extension.
I feel like I am missing something really small but can't figure this out. Please help.
This my App.vue
<template>
<div id="app">
<router-view />
</div>
</template>
This is my Home page:
<template>
<Layout>
<h1>Home page</h1>
</Layout>
</template>
<script>
import Layout from '../layouts/Layout.vue';
export default {
name: 'home',
components: { Layout },
};
</script>
This is Layout component:
<template>
<div class="main">
<Navigation />
<slot />
</div>
</template>
<script>
import Navigation from '../components/Navigation.vue';
export default {
name: 'Layout',
components: { Navigation },
};
</script>
Everything is visible from Layout component except Navigation component. Here it is:
<template>
<div class="navigation">
<router-link :to="{ name: 'home' }">
Home
</router-link>
<nav>
<!-- Nav routes -->
</nav>
</div>
</template>
<script>
export default {
name: 'Navigation',
};
</script>
Related
I am working on a Vue 3 app. I have run into a problem working with a <Navbar /> component and one of its sub-components.
In App.vue:
<template>
<Navbar />
<Content title="Home" />
<Footer />
</template>
<script>
import Navbar from './components/Navbar.vue'
import Content from './components/Content.vue'
import Footer from './components/Footer.vue'
export default {
name: 'App',
components: {
Navbar,
Content,
Footer
}
}
</script>
Within the Content.vue component, I can display the title this way:
<h1>{{ title }}</h1>
<script>
export default {
name: 'Content',
props: {
title: String
}
}
</script>
But displaying buttons with their labels by the same pattern as above does not work:
// Button.vue component
<template>
<button class="btn btn-sm btn-generate">
{{ label }}
</button>
</template>
<script>
export default {
name: 'Button',
props: {
label: String
}
}
</script>
// Navbar.vue component
<template>
<div class="navbar">
<Button label="Button 1" />
<Button label="Button 2" />
</div>
</template>
<script>
import Button from './Button'
export default {
name: 'Navbar',
components: {
Button
}
}
</script>
The problem
As a result of the code above, inside <div class="navbar"> there is only one button with no label, instead of 2 buttons labeled "Button 1" and "Button 2".
Where is my mistake?
I think that naming your component just as the already existing HTML element is not a good idea. Try changing it to MyButton and use <my-button>... in the navbar component (you still want to use <button> in MyButton, as you want to build upon it).
Most probably browser still picks just a default button instead of yours.
The first essential rule mentioned in Vue docs is Use multi-word component names.
You need to bind them so :label="button 1"
I just installed vue-router 4 into a vue 3 application. When setting up my home route I keep getting the application displaying twice and even the navigation twice but cannot figure out why. I tried bringing in the Navigation component into App.vue and Home.vue but still shows twice. Is there something off that I am overlooking here?
router/index.js
import { createWebHistory, createRouter } from "vue-router";
import Home from "../components/Home";
import About from "#/components/About";
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/about",
name: "About",
component: About,
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
Navigation.vue
<template>
<div id="nav">
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
</div>
<router-view/>
</template>
<script>
export default {
name: 'Navigation'
}
</script>
Home.vue
<template>
<Header/>
<Navigation/>
<div>
<About/>
</div>
</template>
App.vue
<template>
<Home/>
</template>
<script>
import Home from "#/components/Home";
export default {
components: {Home}
}
</script>
Home contains Navigation (which contains <router-view>, rendering the current route) and About. Since About is always rendered, you'd see two of them if the current route were /about.
<template>
<Header/>
<Navigation/> <!-- contains router-view -->
<div>
<About/> <!-- ❌ always rendered in addition to current route -->
</div>
</template>
Your current route configuration has no child routes, so there should only be one <router-view>, and it's usually in the root component (App.vue):
App.vue:
<template>
<Header />
<Navigation />
<router-view />
</template>
Navigation.vue:
<template>
<div id="nav">
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
</div>
<!--<router-view/> ❌ move to App.vue -->
</template>
Home.vue:
<template>
<!--<Header/> ❌ move to App.vue -->
<!--<Navigation/> ❌ move to App.vue -->
<div>
<About />
</div>
</template>
demo
I have a problem of nuxt.js
When I try using components in some pages, and layout is 'something' (layout:'something').
But layout always applied default.
Is this a nuxt bug? or there some rules about it?
// pages/main.vue
<template>
<div>
<something />
</div>
</template>
<script>
import something from "#/components/something.vue";
export default {
components: {
something
},
layout: 'a'
};
</script>
.
.
.
// layouts/a.vue
<template>
<v-app class="dark">
<nuxt/>
</v-app>
</template>
<style scoped>
.dark {
background:black;
}
</style>
.
.
.
// components/something.vue
<template>
<div>
Hello
</div>
</template>
Add some paragraph to your layout and check out if its applied:
<template>
<v-app class="dark">
<p>Hello from layout</p>
<nuxt/>
</v-app>
</template>
Are you not suppose to import the v-app component to your layout and then export it?
<script>
import VApp from "#/components/../..
export default {
components: {
VApp
}
</script>
Of course, depending of the location of your v-app component
I just try to follow the example about the use of slot on the Vue official site. But it failed, I have made the code very short
parent component
<template>
<subMenuTemp>
<div class="text" >
parent content
</div>
</subMenuTemp>
</template>
<script>
import subMenuTemp from 'src/test/testChildren.vue'
export default {
data() {
},
components: {
subMenuTemp
}
}
</script>
children component another .vue file
<template>
<div class="content">
<slot>
old content
</slot>
</div>
</template>
<script>
export default {
}
</script>
although the code is very short, I still cannot find where is my fault
Make sure to include the two components in your main.js or some .js file that imports Vue. It should look like this:
import Vue from 'vue'
import App from './App'
import subMenuTemp from './test/testChildren.vue'
new Vue({
el: '#app',
template: '<App/>',
components: { App, subMenuTemp }
})
You don't need to register all components in the main file as pointed in other answers.
You just need to import the child component into the parent component just as you do.
See a here: https://codesandbox.io/s/vue-template-oy15j?fontsize=14
// App.vue
<template>
<div id="app">
<parent-component message="Hello Vue !"/>
</div>
</template>
<script>
import ParentComponent from "./components/ParentComponent";
export default {
name: "App",
components: { ParentComponent }
};
</script>
// ParentComponent.vue
<template>
<child-component>
<div class="test-parent">{{ message }}</div>
</child-component>
</template>
<script>
import ChildComponent from "./ChildComponent";
export default {
name: "ParentComponent",
components: { ChildComponent },
props: {
message: String
}
};
</script>
// ChildComponent.vue
<template>
<div class="test-child">
<slot>default content</slot>
</div>
</template>
<script>
export default {
name: "ChildComponent"
};
</script>
<!-- Result -->
<div id="app">
<div class="test-child">
<div class="test-parent">Hello Vue !</div>
</div>
</div>
Is it possible to hide the vue-router from my login page? If so, how would I do that? On every page I have I see the menu, but on the Login page I don't want to see it.
Here is my code:
Login
<template>
<div>
<h1>Login</h1>
<form action="">
<label>naam</label>
<input type="text">
</form>
</div>
</template>
<script>
</script>
<style scoped>
h1 {
background-color: chartreuse;
}
</style>
App.vue
<template>
<div id="app">
<div class="routing">
</div>
<router-link to="/">Login</router-link>
<router-link to="/home">Home</router-link>
<router-view v-if="$route = 'login'"></router-view>
</div>
</template>
<script>
export default {
data () {
return {
}
}
}
</script>
Main.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App.vue'
import Login from './Login.vue'
import Home from './Home.vue'
Vue.use(VueRouter);
const routes = [
{ path: '/', component: Login},
{ path: '/home', component: Home},
];
const router = new VueRouter({
routes,
mode: 'history'
});
new Vue({
el: '#app',
router,
render: h => h(App)
});
Home.vue
<template>
<div>
<h1>Home</h1>
<hr>
<router-view></router-view>
</div>
</template>
<script>
</script>
<style scoped>
h1 {
background-color: aquamarine;
}
</style>
I just had the same problem and found 2 approaches:
1. Using nested routes - http://router.vuejs.org/en/essentials/nested-routes.html
Basically you have to use your App.vue as kind of a placeholder, with all the elements that are shared between all the pages (in your case I believe that is none), and place <router-view></router-view> inside it. For you I believe that will be as simples as:
//App.vue
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
And you also will have to have another template that will hold your menu:
//Restricted.vue
<template>
<div id="restricted">
<div class="routing">
</div>
<router-link to="/">Login</router-link>
<router-link to="/home">Home</router-link>
<router-view></router-view>
</div>
</template>
And in your router should have something like:
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App.vue'
import Login from './Login.vue'
import Home from './Home.vue'
import Restricted from '/.Restricted.vue';
Vue.use(VueRouter);
const routes = [
{ path: '/', component: Login},
{
path: '/restricted',
component: Restricted,
children: [
{ path: 'home', component: Home},
],
},
];
const router = new VueRouter({
routes,
mode: 'history'
});
new Vue({
el: '#app',
router,
render: h => h(App)
});
This way your Login page will be rendered at / and other pages (with menu) at /restricted/{other_page}. Using this approach the menu will not be displayed nor rendered.
2. Using v-if on the components that you do not want to render.
In you App.vue use v-if="this.$route.path !== '/'" on the elements that you do not want to be rendered, in your case, the router-link's. You could encapsulate them and apply v-if="this.$route.path !== '/'" to the encapsulation element (div?)
//App.vue
<template>
<div id="app">
<div class="routing" v-if="this.$route.path !== '/'">
<router-link to="/">Login</router-link>
<router-link to="/home">Home</router-link>
</div>
<router-view></router-view>
</div>
</template>
Regards.
You can use v-if for this:
<router-link v-if="!isOnLoginPage()" to="/">Login</router-link>
where isOnLoginPage can be a simple method, which returns true or false depending on current route.
isOnLoginPage: function() {
return this.$route.path === '/'
}
if your login path is '/login'
in your App.vue
<template>
<div id="app">
<div class="routing">
</div>
<router-link to="/" v-if="$route.fullPath !== '/login'">Login</router-link>
<router-link to="/home" v-if="$route.fullPath !== '/login'">Home</router-link>
<router-view v-if="$route.fullPath === '/login'"></router-view>
</div>
</template>
<script>
export default {
data () {
return {
}
}
}
</script>