I'm having trouble getting transitions to work for my child routes.
I have the following pages:
pages/
child/
_id.vue
child.vue
index.vue
Navigating between index and any of the child routes triggers transitions, but when navigating from one child route to another child route there is no transition.
Note that there is a static route /child and dynamic routes for /child/_id. The <nuxt-child /> component is inside child.vue:
<template>
<div class="container">
<h1 class="title">
Child Root Page
</h1>
<nuxt-child />
</div>
</template>
<script>
export default {
key(route) {
return route.fullPath
},
}
</script>
If I remove the static route child.vue and move <nuxt-child /> to index.vue all transitions work, but then I don't have the 'parent' child page anymore.
Is it possible to get the transitions to work in this case?
I have a small repo showing the problem and a github page with the site deployed.
Related
I understand paradigm "Page-component" but what if I have a page that renders component, how do I call another component inside this component? Currently nuxtjs does not allow me do it. I can not stick to standart "page-component" scheme as I am bulding cart which calls cart-items.
Say If a cart component which is called by page looks like this, how would it call cart-item component inside it?
<!---- cart component called from index.vue --->
<template>
<div>
<Cart-item></Cart-item> < ---------- This doesn't work.
</div>
</template>
<script>
export default {
props: ['items']
}
</script>
I managed it the standard way:
<template>
<div>
<CartItem></CartItem>
</div>
</template>
<script>
import CartItem from '../components/Cart-item'
export default {
props: ['items']
}
</script>
Since nuxtjs auto-registers all components wonder if there is more graceful way.
EDIT: as promised, here is an example on how to pass some content to a component from another one thanks to slots. This is totally working in any Nuxt page ofc.
NestedContent.vue
<template>
<div>
<p>Here is the NestedContent component and below is a slot passed to ParentWithSlots' component</p>
<hr />
<parent-with-slots>
<!-- <template #default> // this one can be omit since we do use the default slot here -->
<p>This content is inserted into the component ParentWithSlots</p>
<!-- </template> -->
</parent-with-slots>
</div>
</template>
ParentWithSlots.vue
<template>
<div>
<p>xxxxxxxxxxx ParentWithSlots' content before slot xxxxxxxxxxx</p>
<slot>Default content in case none is provided</slot>
<p>xxxxxxxxxxx ParentWithSlots' content after slot xxxxxxxxxxx</p>
</div>
</template>
Here is how it looks
PS: you may also give a try to layouts, it can be useful for overall positioning of some of your components visually.
If your components are in the components directory, you can set components: true in your nuxt.config.js and have access to it pretty much anywhere without any additional step with the <cart-item></cart-item> syntax.
More details here: https://nuxtjs.org/blog/improve-your-developer-experience-with-nuxt-components/
I have an external div that I need to render inside my Vue app. I'm trying to use a slot, like but that's a no go as nothing renders.
Any ideas?
Goal is to have HTML like this (Vue mounts on #app):
<div id="app" data-slot-header="#header"></div>
<div id="header">
<h1>Title here</h1>
</div>
Then the Vue component
<template>
<div>
<slot name="header"></slot>
</div>
</template>
You can use a dynamic <component> and refer to your #header element as a template reference.
For example
new Vue({
data: () => ({
headerComponent: {
template: '#header' // refer to template element by selector
}
}),
}).$mount('#app')
#app:before,#header:before{position:absolute;top:0;right:0;color:rgba(1,1,1,.5);font-size:.8rem}#app{border:1px solid #666;position:relative}#app:before{content:'Vue app'}#header{position:relative;opacity:.5}#header:before{content:'Original header'}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<div id="app">
<p>Dynamic component rendered here 👇</p>
<component :is="headerComponent"></component>
</div>
<div id="header">
<h1>Title here</h1>
</div>
Slots are mainly used with reusable Vue components so that the parent component can render custom stuff inside designated sections of the child. The root component does not have a parent, so it doesn't make sense to use slots for this.
Why can't you just hard-code the div in the template? Or do you need it to be dynamic; will you be swapping out the header contents in some situations? Please provide more information about what your use-case is, otherwise my answer is "just hard-code it".
Take a look at portal-vue. It allows child components to render templates anywhere in the DOM. This might work for your situation.
I started a project using Express and Handlebars and then was encouraged to look at Vue.js. I am still at the stage of reading the docs but so far can't understand how to have layouts, partials and sections in Vue.js. I think a partial would be a component, but I'm lost how to have a layout with partials and sections that I can inject content into.
This is what I do using npm express-handlebars in a file called baselayout.hbs:
<!doctype html>
<html lang="en">
<head>
{{> global/headcode }} <!-- partial view with code for the head tag. it has stuff like favicon links --->
{{{_sections.pagemeta}}} <!-- page specific metadata injected here. this would be meta keywords description etc for a page/view --->
</head>
<body>
<div>
{{> global/siteheader }} <!--- partial view for the site's header --->
<div id="base-Container">
<main id="base-Content" role="main">
{{{ body }}} <!--- a page's main body content goes here --->
</main>
</div>
</div>
{{> sitefooter }}
{{{_sections.pagescripts}}} <!-- section for page-specific scripts injected here --->
</body>
</html>
How could I setup something like the above in Vue.js that would also work with server-side rendering? I just need a base layout with header/footer components included but also sections into which page-specific content can go.
For SSR, you should look at Nuxt.js, Vapper, or one of the other SSR Vue frameworks.
That said, yes, you would use components for everything. Generally, you would have one component for your main layout, then one for each view, then individual components for each partial/section that you would then import into your views and/or main layout. So, for example, based on the above code:
Your main app layout:
// AppLayout.vue
<template>
<div id="app-layout">
<site-header />
<router-view />
<site-footer />
</div>
</template>
<script>
import SiteHeader from './components/global/SiteHeader.vue'
import SiteFooter from './components/global/SiteFooter.vue'
export default {
name: 'AppLayout',
components: {
SiteHeader,
SiteFooter
},
meta: {
// metatags and other head content can be modified using vue-meta or similar
}
}
</script>
Example 'partial' component:
// BaseContainer.vue
<template>
<main id="base-container" role="main">
<h1 class="title">{{ content.title }}</h1>
<img :src="image" alt="" />
<base-content v-html="content.body" />
</main>
</template>
<script>
import BaseContent from './components/content/BaseContent.vue'
export default {
name: 'BaseContainer',
components: {
BaseContent
},
props: {
content: {
type: Object,
default() {
return {}
}
},
image: {
type: String,
default: ''
}
}
}
</script>
Example view component:
// MyView.vue
<template>
<div id="my-view">
<base-container :content="content" :image="image" />
</div>
</template>
<script>
import BaseContainer from './components/BaseContainer.vue'
import content from './data/myContent.json'
import image from './assets/myImage.jpg'
export default {
name: 'MyView',
components: {
BaseContainer
},
data() {
return {
content,
image
}
}
}
</script>
You would then use vue-router to specify which view component to load based on the current URL.
You probably need to use components and slots within your components.
Yes you need to create a component for each of your partials. Each component would have a template.
Then you will have a main component that will put all of this together. Using the more granular components you already have (your partials).
Now if the template structure (html for each component) is coming from the server then you can prob use slots https://v2.vuejs.org/v2/guide/components-slots.html which is a way VueJs allow components to receive custom markup when instantiating the components (see the example in the docs)
For the general layout and UI components of your app you may want to look at https://element.eleme.io/#/en-US/component/layout which is a nice alternative to the more popular Vuetify.
I'm unable to get a layout view to be properly filled with the view-ports I'm specifying in the route config. I have a route "styleguide" which should use the "sidebar" layout, filling the "sidebar" router-view with "sidebar.html" and the "content" router-view with "content.ts / html"
app.ts
export class App {
configureRouter(config: RouterConfiguration, router: Router) {
config.map([{
route: "styleguide",
name: "styleguide",
layoutView: "layout/sidebar.html",
viewPorts: {
sidebar: { moduleId: "styleguide/sidebar.html" },
content: { moduleId: "styleguide/index" },
}
}]);
}
}
app.html
<template>
<router-view layout-view="layout/default.html"></router-view>
</template>
layout/default.html (not used in this example)
<template>
<router-view></router-view>
</template>
layout/sidebar.html
<template>
<router-view name="sidebar"></router-view>
<router-view name="content"></router-view>
</template>
styleguide/sidebar.html
<template>
SIDEBAR!!
</template>
styleguide/index.ts
export class Index { }
styleguide/index.html
<template>
CONTENT
</template>
Issues:
"There was no router-view found in the view for styleguide/sidebar.html." -- Although I have specified the router-view name, etc.
I do have another route which does not specify a layoutView, and thus uses the default. This only works when I replace the router-view element in layout/default.html with slot. I tried to use slots in both layouts but the sidebar layout gives me the same error.
The error you got is because of your app.html doesn't support viewPorts. There is only one <router-view/> with the default name, so with your route configuration with 2 viewports, it failed with the above error.
Layout, according to the documentation, seems like a way to achieve slot like behavior for your routes, not a place to put <router-view/> to me, it seems.
I'd like to have Vue custom components loaded only after the route has been clicked.
Let's say my app's stripped down html structure looks like this:
<div id="admin">
<admin-menu><!-- component with routes --></admin-menu>
<div id="content-container">
<!-- want dynamically loaded Single Page Components here -->
</div>
</div>
I'd like content container to be the target, where the dynamically loaded Single Page Components should be placed.
The one thing I don't want is to predefine the custom components in the content container right from the start like this:
<div id="admin">
<admin-menu><!-- component with routes --></admin-menu>
<div id="content-container">
<my-component-1></my-component-1>
<my-component-2></my-component-2>
<my-component-3></my-component-3>
<my-component-N></my-component-N>
</div>
</div>
If I do that, they must be registered i.e. loaded when vue hits them on startup of the app and but I'd like the components to be lazy loading.
So how can I initialize and place a single file component in the target content-container only after the respective router link has been clicked?