mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
Dynamic layout feature
This commit is contained in:
parent
fb7b856343
commit
b6856928db
@ -55,22 +55,28 @@ function loadAsyncComponents (to, from, next) {
|
||||
}
|
||||
|
||||
function callMiddleware (Components, context, layout) {
|
||||
// Call middleware
|
||||
// if layout is undefined, only call global middleware
|
||||
let midd = <%= serialize(router.middleware, { isJSON: true }) %>
|
||||
if (layout.middleware) {
|
||||
midd = midd.concat(layout.middleware)
|
||||
}
|
||||
Components.forEach((Component) => {
|
||||
if (Component.options.middleware) {
|
||||
midd = midd.concat(Component.options.middleware)
|
||||
let unknownMiddleware = false
|
||||
if (typeof layout !== 'undefined') {
|
||||
midd = [] // exclude global middleware if layout defined (already called before)
|
||||
if (layout.middleware) {
|
||||
midd = midd.concat(layout.middleware)
|
||||
}
|
||||
})
|
||||
Components.forEach((Component) => {
|
||||
if (Component.options.middleware) {
|
||||
midd = midd.concat(Component.options.middleware)
|
||||
}
|
||||
})
|
||||
}
|
||||
midd = midd.map((name) => {
|
||||
if (typeof middleware[name] !== 'function') {
|
||||
unknownMiddleware = true
|
||||
this.error({ statusCode: 500, message: 'Unknown middleware ' + name })
|
||||
}
|
||||
return middleware[name]
|
||||
})
|
||||
if (unknownMiddleware) return
|
||||
return promiseSeries(midd, context)
|
||||
}
|
||||
|
||||
@ -81,13 +87,15 @@ function render (to, from, next) {
|
||||
nextCalled = true
|
||||
next(path)
|
||||
}
|
||||
const context = getContext({ to<%= (store ? ', store' : '') %>, isClient: true, next: _next.bind(this), error: this.error.bind(this) })
|
||||
let context = getContext({ to<%= (store ? ', store' : '') %>, isClient: true, next: _next.bind(this), error: this.error.bind(this) })
|
||||
let Components = getMatchedComponents(to)
|
||||
this._context = context
|
||||
this._dateLastError = this.$options._nuxt.dateErr
|
||||
this._hadError = !!this.$options._nuxt.err
|
||||
if (!Components.length) {
|
||||
// Default layout
|
||||
this.loadLayout(NuxtError.layout)
|
||||
callMiddleware.call(this, Components, context)
|
||||
.then(() => this.loadLayout(typeof NuxtError.layout === 'function' ? NuxtError.layout(context) : NuxtError.layout))
|
||||
.then(callMiddleware.bind(this, Components, context))
|
||||
.then(() => {
|
||||
this.error({ statusCode: 404, message: 'This page could not be found.' })
|
||||
@ -105,7 +113,14 @@ function render (to, from, next) {
|
||||
this.setTransitions(mapTransitions(Components, to, from))
|
||||
let nextCalled = false
|
||||
// Set layout
|
||||
this.loadLayout(Components[0].options.layout)
|
||||
callMiddleware.call(this, Components, context)
|
||||
.then(() => {
|
||||
let layout = Components[0].options.layout
|
||||
if (typeof layout === 'function') {
|
||||
layout = layout(context)
|
||||
}
|
||||
return this.loadLayout(layout)
|
||||
})
|
||||
.then(callMiddleware.bind(this, Components, context))
|
||||
.then(() => {
|
||||
// Pass validation?
|
||||
@ -169,7 +184,11 @@ function render (to, from, next) {
|
||||
.catch((error) => {
|
||||
_lastPaths = []
|
||||
error.statusCode = error.statusCode || error.status || (error.response && error.response.status) || 500
|
||||
this.loadLayout(NuxtError.layout)
|
||||
let layout = NuxtError.layout
|
||||
if (typeof layout === 'function') {
|
||||
layout = layout(context)
|
||||
}
|
||||
this.loadLayout(layout)
|
||||
.then(() => {
|
||||
this.error(error)
|
||||
next(false)
|
||||
@ -211,7 +230,11 @@ function fixPrepatch (to, ___) {
|
||||
this.error()
|
||||
}
|
||||
// Set layout
|
||||
this.setLayout(this.$options._nuxt.err ? NuxtError.layout : to.matched[0].components.default.options.layout)
|
||||
let layout = this.$options._nuxt.err ? NuxtError.layout : to.matched[0].components.default.options.layout
|
||||
if (typeof layout === 'function') {
|
||||
layout = layout(this._context)
|
||||
}
|
||||
this.setLayout(layout)
|
||||
// hot reloading
|
||||
Vue.nextTick(() => hotReloadAPI(this))
|
||||
})
|
||||
@ -246,7 +269,8 @@ function addHotReload ($component, depth) {
|
||||
$component.$vnode.data._hasHotReload = true
|
||||
var _forceUpdate = $component.$forceUpdate.bind($component.$parent)
|
||||
$component.$vnode.context.$forceUpdate = () => {
|
||||
let Component = getMatchedComponents(router.currentRoute)[depth]
|
||||
let Components = getMatchedComponents(router.currentRoute)
|
||||
let Component = Components[depth]
|
||||
if (!Component) return _forceUpdate()
|
||||
if (typeof Component === 'object' && !Component.options) {
|
||||
// Updated via vue-router resolveAsyncComponents()
|
||||
@ -255,41 +279,51 @@ function addHotReload ($component, depth) {
|
||||
}
|
||||
this.error()
|
||||
let promises = []
|
||||
if (depth === 0) {
|
||||
// If layout changed
|
||||
Component.options.layout = Component.options.layout || 'default'
|
||||
if (this.layoutName !== Component.options.layout) {
|
||||
let promise = this.loadLayout(Component.options.layout)
|
||||
promise.then(() => {
|
||||
this.setLayout(Component.options.layout)
|
||||
Vue.nextTick(() => hotReloadAPI(this))
|
||||
})
|
||||
promises.push(promise)
|
||||
}
|
||||
}
|
||||
const next = function (path) {
|
||||
<%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %>
|
||||
router.push(path)
|
||||
}
|
||||
const context = getContext({ route: router.currentRoute<%= (store ? ', store' : '') %>, isClient: true, next: next.bind(this), error: this.error })
|
||||
// Call asyncData()
|
||||
let pAsyncData = promisify(Component.options.asyncData || noopData, context)
|
||||
pAsyncData.then((asyncDataResult) => {
|
||||
let data = (typeof Component.options.data === 'function' ? Component.options.data() : noopData())
|
||||
data = Object.assign(data, asyncDataResult)
|
||||
Component.options.data = () => data
|
||||
Component._Ctor.options.data = Component.options.data
|
||||
<%= (loading ? 'this.$loading.increase && this.$loading.increase(30)' : '') %>
|
||||
})
|
||||
promises.push(pAsyncData)
|
||||
// Call fetch()
|
||||
Component.options.fetch = Component.options.fetch || noopFetch
|
||||
let pFetch = Component.options.fetch(context)
|
||||
if (!(pFetch instanceof Promise)) { pFetch = Promise.resolve(pFetch) }
|
||||
<%= (loading ? 'pFetch.then(() => this.$loading.increase && this.$loading.increase(30))' : '') %>
|
||||
promises.push(pFetch)
|
||||
let context = getContext({ route: router.currentRoute<%= (store ? ', store' : '') %>, isClient: true, next: next.bind(this), error: this.error })
|
||||
<%= (loading ? 'this.$loading.start && this.$loading.start()' : '') %>
|
||||
return Promise.all(promises).then(() => {
|
||||
callMiddleware.call(this, Components, context)
|
||||
.then(() => {
|
||||
// If layout changed
|
||||
if (depth !== 0) return Promise.resolve()
|
||||
let layout = Component.options.layout || 'default'
|
||||
if (typeof layout === 'function') {
|
||||
layout = layout(context)
|
||||
}
|
||||
if (this.layoutName === layout) return Promise.resolve()
|
||||
let promise = this.loadLayout(layout)
|
||||
promise.then(() => {
|
||||
this.setLayout(layout)
|
||||
Vue.nextTick(() => hotReloadAPI(this))
|
||||
})
|
||||
return promise
|
||||
})
|
||||
.then(() => {
|
||||
return callMiddleware.call(this, Components, context, this.layout)
|
||||
})
|
||||
.then(() => {
|
||||
// Call asyncData()
|
||||
let pAsyncData = promisify(Component.options.asyncData || noopData, context)
|
||||
pAsyncData.then((asyncDataResult) => {
|
||||
let data = (typeof Component.options.data === 'function' ? Component.options.data() : noopData())
|
||||
data = Object.assign(data, asyncDataResult)
|
||||
Component.options.data = () => data
|
||||
Component._Ctor.options.data = Component.options.data
|
||||
<%= (loading ? 'this.$loading.increase && this.$loading.increase(30)' : '') %>
|
||||
})
|
||||
promises.push(pAsyncData)
|
||||
// Call fetch()
|
||||
Component.options.fetch = Component.options.fetch || noopFetch
|
||||
let pFetch = Component.options.fetch(context)
|
||||
if (!(pFetch instanceof Promise)) { pFetch = Promise.resolve(pFetch) }
|
||||
<%= (loading ? 'pFetch.then(() => this.$loading.increase && this.$loading.increase(30))' : '') %>
|
||||
promises.push(pFetch)
|
||||
return Promise.all(promises)
|
||||
})
|
||||
.then(() => {
|
||||
<%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %>
|
||||
_forceUpdate()
|
||||
setTimeout(() => hotReloadAPI(this), 100)
|
||||
@ -352,10 +386,18 @@ Promise.all(resolveComponents)
|
||||
.then((Components) => {
|
||||
const _app = new Vue(app)
|
||||
|
||||
let layout = Components.length ? Components[0].options.layout : NuxtError.layout
|
||||
return _app.loadLayout(layout)
|
||||
let context = getContext({ to: router.currentRoute, isClient: true })
|
||||
let layoutName = 'default'
|
||||
return callMiddleware.call(_app, Components, context)
|
||||
.then(() => {
|
||||
_app.setLayout(layout)
|
||||
layoutName = Components.length ? Components[0].options.layout : NuxtError.layout
|
||||
if (typeof layoutName === 'function') {
|
||||
layoutName = layoutName(context)
|
||||
}
|
||||
return _app.loadLayout(layoutName)
|
||||
})
|
||||
.then(() => {
|
||||
_app.setLayout(layoutName)
|
||||
return { _app, Components }
|
||||
})
|
||||
})
|
||||
|
@ -50,7 +50,7 @@ export default context => {
|
||||
context.error = _app.$options._nuxt.error.bind(_app)
|
||||
|
||||
<%= (isDev ? 'const s = isDev && Date.now()' : '') %>
|
||||
const ctx = getContext(context)
|
||||
let ctx = getContext(context)
|
||||
let Components = getMatchedComponents(context.route)
|
||||
<% if (store) { %>
|
||||
let promise = (store._actions && store._actions.nuxtServerInit ? store.dispatch('nuxtServerInit', omit(getContext(context), 'redirect', 'error')) : null)
|
||||
@ -72,12 +72,28 @@ export default context => {
|
||||
}
|
||||
return Component
|
||||
})
|
||||
// Call global middleware (nuxt.config.js)
|
||||
let midd = <%= serialize(router.middleware, { isJSON: true }) %>
|
||||
midd = midd.map((name) => {
|
||||
if (typeof middleware[name] !== 'function') {
|
||||
context.nuxt.error = context.error({ statusCode: 500, message: 'Unknown middleware ' + name })
|
||||
}
|
||||
return middleware[name]
|
||||
})
|
||||
if (context.nuxt.error) return
|
||||
return promiseSeries(midd, ctx)
|
||||
})
|
||||
.then(() => {
|
||||
// Set layout
|
||||
return _app.setLayout(Components.length ? Components[0].options.layout : NuxtError.layout)
|
||||
let layout = Components.length ? Components[0].options.layout : NuxtError.layout
|
||||
if (typeof layout === 'function') {
|
||||
layout = layout(ctx)
|
||||
}
|
||||
return _app.setLayout(layout)
|
||||
})
|
||||
.then((layout) => {
|
||||
// Call middleware
|
||||
let midd = <%= serialize(router.middleware, { isJSON: true }) %>
|
||||
// Call middleware (layout + pages)
|
||||
let midd = []
|
||||
if (layout.middleware) {
|
||||
midd = midd.concat(layout.middleware)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user