Comments (13)
For this effect, I'd recommend using layouts a little bit differently. Instead of defining them in your view components, you could define them as a meta property on your routes (potentially with a default to fall back on). Below is an example refactor that I believe should achieve what you want. 🙂
diff --git a/src/app.vue b/src/app.vue
index 6857411..b9702a8 100644
--- a/src/app.vue
+++ b/src/app.vue
@@ -9,6 +9,14 @@ export default {
return title ? `${title} | ${appConfig.title}` : appConfig.title
},
},
+ computed: {
+ LayoutComponent() {
+ return (
+ (this.$route.meta && this.$route.meta.layout) ||
+ require('@layouts/main').default
+ )
+ },
+ },
}
</script>
@@ -18,7 +26,22 @@ export default {
Even when routes use the same component, treat them
as distinct and create the component again.
-->
- <router-view :key="$route.fullPath"/>
+ <transition
+ name="fade"
+ mode="out-in"
+ >
+ <component
+ :is="LayoutComponent"
+ :key="LayoutComponent.name || LayoutComponent.__file"
+ >
+ <transition
+ name="fade"
+ mode="out-in"
+ >
+ <router-view :key="fullPath"/>
+ </transition>
+ </component>
+ </transition>
</div>
</template>
@@ -88,4 +111,17 @@ h6 {
#nprogress .bar {
background: $color-link-text;
}
+
+// ===
+// Transitions
+// ===
+
+.fade-enter-active,
+.fade-leave-active {
+ transition: opacity 0.5s;
+}
+.fade-enter,
+.fade-leave-to {
+ opacity: 0;
+}
</style>
diff --git a/src/router/views/404.vue b/src/router/views/404.vue
index 4ce46e9..1921d60 100644
--- a/src/router/views/404.vue
+++ b/src/router/views/404.vue
@@ -1,12 +1,9 @@
<script>
-import Layout from '@layouts/main'
-
export default {
page: {
title: '404',
meta: [{ name: 'description', content: '404' }],
},
- components: { Layout },
props: {
resource: {
type: String,
@@ -17,15 +14,13 @@ export default {
</script>
<template>
- <Layout>
- <h1 :class="$style.title">
- 404
- <span v-if="resource">
- {{ resource }}
- </span>
- Not Found
- </h1>
- </Layout>
+ <h1 :class="$style.title">
+ 404
+ <span v-if="resource">
+ {{ resource }}
+ </span>
+ Not Found
+ </h1>
</template>
<style lang="scss" module>
diff --git a/src/router/views/home.vue b/src/router/views/home.vue
index 540e538..dc71078 100644
--- a/src/router/views/home.vue
+++ b/src/router/views/home.vue
@@ -1,22 +1,20 @@
<script>
import appConfig from '@src/app.config'
-import Layout from '@layouts/main'
export default {
page: {
title: 'Home',
meta: [{ name: 'description', content: appConfig.description }],
},
- components: { Layout },
}
</script>
<template>
- <Layout>
+ <div>
<h1>Home Page</h1>
<img
src="@assets/images/logo.png"
alt="Logo"
>
- </Layout>
+ </div>
</template>
diff --git a/src/router/views/loading.vue b/src/router/views/loading.vue
index df01943..eaf6e8f 100644
--- a/src/router/views/loading.vue
+++ b/src/router/views/loading.vue
@@ -1,25 +1,20 @@
<script>
-import Layout from '@layouts/main'
-
export default {
page: {
title: 'Loading page...',
meta: [{ name: 'description', content: 'Loading page...' }],
},
- components: { Layout },
}
</script>
<template>
- <Layout>
- <transition appear>
- <BaseIcon
- :class="$style.loadingIcon"
- name="sync"
- spin
- />
- </transition>
- </Layout>
+ <transition appear>
+ <BaseIcon
+ :class="$style.loadingIcon"
+ name="sync"
+ spin
+ />
+ </transition>
</template>
<style lang="scss" module>
diff --git a/src/router/views/login.vue b/src/router/views/login.vue
index 7352feb..0f17226 100644
--- a/src/router/views/login.vue
+++ b/src/router/views/login.vue
@@ -1,5 +1,4 @@
<script>
-import Layout from '@layouts/main'
import { authMethods } from '@state/helpers'
import appConfig from '@src/app.config'
@@ -8,7 +7,6 @@ export default {
title: 'Log in',
meta: [{ name: 'description', content: `Log in to ${appConfig.title}` }],
},
- components: { Layout },
data() {
return {
username: '',
@@ -43,36 +41,34 @@ export default {
</script>
<template>
- <Layout>
- <form
- :class="$style.form"
- @submit.prevent="tryToLogIn"
+ <form
+ :class="$style.form"
+ @submit.prevent="tryToLogIn"
+ >
+ <BaseInput
+ v-model="username"
+ name="username"
+ />
+ <BaseInput
+ v-model="password"
+ name="password"
+ type="password"
+ />
+ <BaseButton
+ :disabled="tryingToLogIn"
+ type="submit"
>
- <BaseInput
- v-model="username"
- name="username"
+ <BaseIcon
+ v-if="tryingToLogIn"
+ name="sync"
+ spin
/>
- <BaseInput
- v-model="password"
- name="password"
- type="password"
- />
- <BaseButton
- :disabled="tryingToLogIn"
- type="submit"
- >
- <BaseIcon
- v-if="tryingToLogIn"
- name="sync"
- spin
- />
- <span v-else>Log in</span>
- </BaseButton>
- <p v-if="authError">
- There was an error logging in to your account.
- </p>
- </form>
- </Layout>
+ <span v-else>Log in</span>
+ </BaseButton>
+ <p v-if="authError">
+ There was an error logging in to your account.
+ </p>
+ </form>
</template>
<style lang="scss" module>
diff --git a/src/router/views/profile.vue b/src/router/views/profile.vue
index 3a500f3..ea57ae4 100644
--- a/src/router/views/profile.vue
+++ b/src/router/views/profile.vue
@@ -1,6 +1,4 @@
<script>
-import Layout from '@layouts/main'
-
export default {
page() {
return {
@@ -13,7 +11,6 @@ export default {
],
}
},
- components: { Layout },
props: {
user: {
type: Object,
@@ -24,12 +21,12 @@ export default {
</script>
<template>
- <Layout>
+ <div>
<h1>
<BaseIcon name="user"/>
{{ user.name }}
Profile
</h1>
<pre>{{ user }}</pre>
- </Layout>
+ </div>
</template>
diff --git a/src/router/views/timeout.vue b/src/router/views/timeout.vue
index 97a96d8..af443af 100644
--- a/src/router/views/timeout.vue
+++ b/src/router/views/timeout.vue
@@ -1,6 +1,4 @@
<script>
-import Layout from '@layouts/main'
-
export default {
page: {
title: 'Page timeout',
@@ -8,16 +6,13 @@ export default {
{ name: 'description', content: 'The page timed out while loading.' },
],
},
- components: { Layout },
}
</script>
<template>
- <Layout>
- <h1 :class="$style.title">
- The page timed out while loading
- </h1>
- </Layout>
+ <h1 :class="$style.title">
+ The page timed out while loading
+ </h1>
</template>
<style lang="scss" module>
Let me know if that solves the problem for you.
from vue-enterprise-boilerplate.
@dnewkerk Did you ever find a solution to the multiple named slots issue?
I'm facing the same problem now and the only ways I could think of fixing it are:
- include content for all named slots in route meta data.
- maybe use something like portal-vue
Both solutions seem don't feel quite right for me, so I'm hoping you are willing to share what you came up with?
from vue-enterprise-boilerplate.
It did indeed! Thanks, @chrisvfritz, you're the best.
from vue-enterprise-boilerplate.
@marceloavf The easiest way might be to add something like a new currentRouteStatus
property to the router, e.g. in src/router/index.js
:
router.currentRouteStatus = Vue.observable({
isLoaded: false,
})
router.beforeEach((routeTo, routeFrom, next) => {
router.currentRouteStatus.isLoaded = !routeTo.matched.some(
(route) =>
typeof route.components === 'function' ||
typeof route.components.default === 'function'
)
// ...
Then update isLoaded
inside the AsyncHandler
:
function lazyLoadView(AsyncView) {
const AsyncHandler = () => ({
component: AsyncView.then((componentConfig) => {
require('@router').default.currentRouteStatus.isLoaded = true
return componentConfig
}),
// ...
And finally, inside the template of app.vue
, you could check $router.currentRouteStatus.isLoaded
to see if the current route is loaded and only render the layout if it is. I haven't tested this strategy, so there may be edge cases I'm not currently thinking of, but this should give you a starting point. 🙂
from vue-enterprise-boilerplate.
@marceloavf Great question. In order to prevent it from interfering, you'd have to render the <RouterView>
without a wrapping layout when the current route is not loaded, rather than just rendering nothing.
from vue-enterprise-boilerplate.
@dnewkerk Hopefully you've solved the issue on your own by now, but you may want $route.path
in that case rather than $route.fullPath
(see the Vue Router docs for the difference).
Also, I'm reopening this as I'm thinking about updating the routing strategy to something along these lines, as I've had a number of projects that have needed this kind of strategy and am thinking there might be more advantages than disadvantages for most projects.
from vue-enterprise-boilerplate.
I'm going to assume this solves the problem, but happy to reopen if it doesn't. 🙂
from vue-enterprise-boilerplate.
Hey @chrisvfritz, you did an awesome refactor here!
I implemented this content in my project but I got a little problem,
On the first load, it always show a little of the default layout until it gets totally loaded and goes to the desired layout specified in the meta, is there a way to solve this?
I was thinking about making a "loading" kind of layout to be the default and set the main to everyone else, but I don't think it's the best solution :/
from vue-enterprise-boilerplate.
@marceloavf That idea with the loading layout sounds fine actually. 🙂 You'd just have to always define a layout. You could also simply not have a default layout, or only show the default layout after the component for the current route has finished downloading.
from vue-enterprise-boilerplate.
Nice @chrisvfritz, I was thinking about this last idea, but I couldn't find a way to implement this. 😞
from vue-enterprise-boilerplate.
Works like charm @chrisvfritz, just a question, this code will not block this one from lazyLoadView?
// A component to use while the component is loading.
loading: require('@views/_loading').default,
// Delay before showing the loading component.
// Default: 200 (milliseconds).
delay: 400,
from vue-enterprise-boilerplate.
@chrisvfritz thanks for the alternate way of using layouts above. I ran into a similar issue with the layout being re-rendered on route changes. For reference, the app I'm working on (tagnifi.com) has a filterable data table, and the selected filter params get persisted in the URL so the filtered search can be saved/shared. However every filter change causes the layout to re-render, so the form loses the current tab index, some temporary state on the page is lost, etc.
I tried using the alternate approach you provided above, and while it resolves the above issue with route changes, I can't figure out now if/how I can use multiple named slots in my layout. The filter area appears in a specific spot of the layout using <template v-slot:before-content>...</template>
(it stays sticky at the top of the page while only the results scroll) though I get compile errors now when trying to do this without the Layout wrapper in my component.
Anyhow if you might be able to point me in the right direction, it would be greatly appreciated. Thanks!
from vue-enterprise-boilerplate.
@chrisvfritz is there a branch that contains the code changes illustrated inside this comment? Thanks!
from vue-enterprise-boilerplate.
Related Issues (20)
- Stylelint error on fresh install
- compile problem related to new source HOT 1
- Relative imports from parent directories are not allowed. HOT 2
- pre-commit doesn't do anything ! HOT 2
- Error Test in E2E
- Add template feature to repo?
- Failed Netlify deploy
- Error in test unit. something wrong with config, maybe HOT 1
- Will we update this boilerplate to vue3? HOT 3
- Where can I find examples of using this boilerplate? HOT 1
- sass-loader unable to load from updated .scss files
- Dependency Injection into Vuex Modules HOT 3
- Is this a typo or intentional? HOT 1
- TypeError: ext[key].bind is not a function HOT 3
- Getting issue while importing new component and not getting type suggestion HOT 1
- Problem setting environment variable API_BASE_URL HOT 1
- Change app.config.json at runtime
- Where do I set backend url for production?
- After "yarn upgrade" it breaks :( - Windows 10 HOT 1
- Updated dependencies release?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from vue-enterprise-boilerplate.