From e937937ea1f288fc0d066939d819aa990f52958e Mon Sep 17 00:00:00 2001 From: James Homer Date: Fri, 8 Sep 2017 11:42:00 +0100 Subject: [PATCH] add layout transitions --- examples/layout-transitions/README.md | 3 + examples/layout-transitions/assets/main.css | 52 ++++++++++++++ .../layout-transitions/layouts/secondary.vue | 11 +++ examples/layout-transitions/nuxt.config.js | 10 +++ examples/layout-transitions/package.json | 12 ++++ examples/layout-transitions/pages/about.vue | 13 ++++ examples/layout-transitions/pages/index.vue | 7 ++ examples/layout-transitions/pages/users.vue | 71 +++++++++++++++++++ lib/app/App.vue | 4 +- lib/app/components/nuxt-child.js | 18 ++++- lib/builder/builder.js | 1 + lib/common/options.js | 7 ++ 12 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 examples/layout-transitions/README.md create mode 100644 examples/layout-transitions/assets/main.css create mode 100644 examples/layout-transitions/layouts/secondary.vue create mode 100644 examples/layout-transitions/nuxt.config.js create mode 100644 examples/layout-transitions/package.json create mode 100644 examples/layout-transitions/pages/about.vue create mode 100644 examples/layout-transitions/pages/index.vue create mode 100644 examples/layout-transitions/pages/users.vue diff --git a/examples/layout-transitions/README.md b/examples/layout-transitions/README.md new file mode 100644 index 000000000..3bdd2a909 --- /dev/null +++ b/examples/layout-transitions/README.md @@ -0,0 +1,3 @@ +# Layout transitions with Nuxt.js + +https://nuxtjs.org/examples/layout-transitions diff --git a/examples/layout-transitions/assets/main.css b/examples/layout-transitions/assets/main.css new file mode 100644 index 000000000..dbb73ba00 --- /dev/null +++ b/examples/layout-transitions/assets/main.css @@ -0,0 +1,52 @@ +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; +} + +.container { + text-align: center; + padding-top: 200px; + font-size: 20px; + transition: all .5s cubic-bezier(.55,0,.1,1); +} + +.page-enter-active, .page-leave-active { + transition: opacity .5s +} +.page-enter, .page-leave-active { + opacity: 0 +} + +.layout-enter-active, .layout-leave-active { + transition: opacity .5s +} +.layout-enter, .layout-leave-active { + opacity: 0 +} + +.bounce-enter-active { + animation: bounce-in .8s; +} +.bounce-leave-active { + animation: bounce-out .5s; +} +@keyframes bounce-in { + 0% { transform: scale(0) } + 50% { transform: scale(1.5) } + 100% { transform: scale(1) } +} +@keyframes bounce-out { + 0% { transform: scale(1) } + 50% { transform: scale(1.5) } + 100% { transform: scale(0) } +} + +.slide-left-enter, +.slide-right-leave-active { + opacity: 0; + transform: translate(30px, 0); +} +.slide-left-leave-active, +.slide-right-enter { + opacity: 0; + transform: translate(-30px, 0); +} diff --git a/examples/layout-transitions/layouts/secondary.vue b/examples/layout-transitions/layouts/secondary.vue new file mode 100644 index 000000000..d4a9065bd --- /dev/null +++ b/examples/layout-transitions/layouts/secondary.vue @@ -0,0 +1,11 @@ + diff --git a/examples/layout-transitions/nuxt.config.js b/examples/layout-transitions/nuxt.config.js new file mode 100644 index 000000000..e1b2d64a6 --- /dev/null +++ b/examples/layout-transitions/nuxt.config.js @@ -0,0 +1,10 @@ +module.exports = { + build: { + vendor: ['axios'] + }, + css: ['~/assets/main.css'], + layoutTransition: { + name: 'layout', + mode: 'out-in' + } +} diff --git a/examples/layout-transitions/package.json b/examples/layout-transitions/package.json new file mode 100644 index 000000000..38fd64e26 --- /dev/null +++ b/examples/layout-transitions/package.json @@ -0,0 +1,12 @@ +{ + "name": "nuxt-layout-transitions", + "dependencies": { + "axios": "^0.15.3", + "nuxt": "latest" + }, + "scripts": { + "dev": "../../bin/nuxt", + "build": "nuxt build", + "start": "nuxt start" + } +} diff --git a/examples/layout-transitions/pages/about.vue b/examples/layout-transitions/pages/about.vue new file mode 100644 index 000000000..0ec094454 --- /dev/null +++ b/examples/layout-transitions/pages/about.vue @@ -0,0 +1,13 @@ + + + diff --git a/examples/layout-transitions/pages/index.vue b/examples/layout-transitions/pages/index.vue new file mode 100644 index 000000000..fe5ce7400 --- /dev/null +++ b/examples/layout-transitions/pages/index.vue @@ -0,0 +1,7 @@ + diff --git a/examples/layout-transitions/pages/users.vue b/examples/layout-transitions/pages/users.vue new file mode 100644 index 000000000..ce5c065ba --- /dev/null +++ b/examples/layout-transitions/pages/users.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/lib/app/App.vue b/lib/app/App.vue index 37e6d69b3..53806cd92 100644 --- a/lib/app/App.vue +++ b/lib/app/App.vue @@ -1,7 +1,9 @@ diff --git a/lib/app/components/nuxt-child.js b/lib/app/components/nuxt-child.js index 39b8e3c4e..5e17edbea 100644 --- a/lib/app/components/nuxt-child.js +++ b/lib/app/components/nuxt-child.js @@ -37,6 +37,19 @@ export default { name: 'nuxt-child', functional: true, render (h, { parent, data }) { + const nuxt = parent.$root.nuxt + const component = parent.$route.matched[0].components.default + + const layoutUid = parent._uid + const layoutName = component.options ? component.options.layout : null + + // If we're changing layout return the stored vnode + if (nuxt._layoutUid === layoutUid && + nuxt._layoutName !== layoutName) return nuxt._layoutVnode + + nuxt._layoutUid = layoutUid + nuxt._layoutName = layoutName + data.nuxtChild = true const _parent = parent const transitions = parent.$nuxt.nuxt.transitions @@ -62,11 +75,14 @@ export default { listeners[key] = transition[key].bind(_parent) } }) - return h('transition', { + + nuxt._layoutVnode = h('transition', { props: transitionProps, on: listeners }, [ h('router-view', data) ]) + + return nuxt._layoutVnode } } diff --git a/lib/builder/builder.js b/lib/builder/builder.js index cf1de0225..ec84c5913 100644 --- a/lib/builder/builder.js +++ b/lib/builder/builder.js @@ -219,6 +219,7 @@ export default class Builder extends Tapable { layouts: Object.assign({}, this.options.layouts), loading: typeof this.options.loading === 'string' ? this.relativeToBuild(this.options.srcDir, this.options.loading) : this.options.loading, transition: this.options.transition, + layoutTransition: this.options.layoutTransition, components: { ErrorPage: this.options.ErrorPage ? this.relativeToBuild(this.options.ErrorPage) : null } diff --git a/lib/common/options.js b/lib/common/options.js index 8c6f09931..7f0e5b8d3 100755 --- a/lib/common/options.js +++ b/lib/common/options.js @@ -24,6 +24,9 @@ Options.from = function (_options) { if (typeof options.transition === 'string') { options.transition = { name: options.transition } } + if (typeof options.layoutTransition === 'string') { + options.layoutTransition = { name: options.layoutTransition } + } // Apply defaults _.defaultsDeep(options, Options.defaults) @@ -243,6 +246,10 @@ Options.defaults = { appearActiveClass: 'appear-active', appearToClass: 'appear-to' }, + layoutTransition: { + name: 'layout', + mode: 'out-in' + }, router: { mode: 'history', base: '/',