mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-18 01:15:58 +00:00
refactor: extract <NuxtLayout>
from <NuxtPage>
(#3011)
This commit is contained in:
parent
47dfb7b519
commit
083f90b719
@ -25,7 +25,9 @@ If you have a [`pages/`](/docs/directory-structure/pages) directory, to display
|
||||
```vue [app.vue]
|
||||
<template>
|
||||
<div>
|
||||
<NuxtPage/>
|
||||
<NuxtLayout>
|
||||
<NuxtPage/>
|
||||
</NuxtLayout>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
@ -1,3 +1,5 @@
|
||||
<template>
|
||||
<NuxtPage />
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
@ -1,24 +1,33 @@
|
||||
import { defineComponent, h, Ref } from 'vue'
|
||||
import { defineComponent, isRef, Ref, Transition } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { wrapIf } from './utils'
|
||||
// @ts-ignore
|
||||
import layouts from '#build/layouts'
|
||||
|
||||
const defaultLayoutTransition = { name: 'layout', mode: 'out-in' }
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
name: {
|
||||
type: [String, Boolean, Object] as unknown as () => string | false | Ref<string | false>,
|
||||
default: 'default'
|
||||
default: null
|
||||
}
|
||||
},
|
||||
setup (props, context) {
|
||||
const route = useRoute()
|
||||
|
||||
return () => {
|
||||
const layout = (props.name && typeof props.name === 'object' ? props.name.value : props.name) ?? 'default'
|
||||
if (!layouts[layout]) {
|
||||
if (process.dev && layout && layout !== 'default') {
|
||||
console.warn(`Invalid layout \`${layout}\` selected.`)
|
||||
}
|
||||
return context.slots.default()
|
||||
const layout = (isRef(props.name) ? props.name.value : props.name) ?? route.meta.layout as string ?? 'default'
|
||||
|
||||
const hasLayout = layout && layout in layouts
|
||||
if (process.dev && layout && !hasLayout && layout !== 'default') {
|
||||
console.warn(`Invalid layout \`${layout}\` selected.`)
|
||||
}
|
||||
return h(layouts[layout], props, context.slots)
|
||||
|
||||
// We avoid rendering layout transition if there is no layout to render
|
||||
return wrapIf(Transition, hasLayout && (route.meta.layoutTransition ?? defaultLayoutTransition),
|
||||
wrapIf(layouts[layout], hasLayout, context.slots)
|
||||
).default()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1,59 +1,27 @@
|
||||
import { Component, defineComponent, KeepAlive, h, Suspense, Transition } from 'vue'
|
||||
import { RouterView, useRoute } from 'vue-router'
|
||||
import NuxtLayout from './layout'
|
||||
import { defineComponent, h, Suspense, Transition } from 'vue'
|
||||
import { RouterView } from 'vue-router'
|
||||
import { wrapIf, wrapInKeepAlive } from './utils'
|
||||
import { useNuxtApp } from '#app'
|
||||
// @ts-ignore
|
||||
import layouts from '#build/layouts'
|
||||
|
||||
type InstanceOf<T> = T extends new (...args: any[]) => infer R ? R : never
|
||||
type RouterViewSlotProps = Parameters<InstanceOf<typeof RouterView>['$slots']['default']>[0]
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NuxtPage',
|
||||
props: {
|
||||
layout: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
setup () {
|
||||
const nuxtApp = useNuxtApp()
|
||||
const route = useRoute()
|
||||
|
||||
return () => {
|
||||
// We avoid rendering layout transition if there is no layout to render
|
||||
const hasLayout = props.layout ?? route.meta.layout ?? 'default' in layouts
|
||||
|
||||
return h(RouterView, {}, {
|
||||
default: ({ Component }: RouterViewSlotProps) => Component &&
|
||||
wrapIf(Transition, hasLayout && (route.meta.layoutTransition ?? defaultLayoutTransition),
|
||||
wrapIf(NuxtLayout, hasLayout && { name: props.layout ?? route.meta.layout },
|
||||
default: ({ Component, route }: RouterViewSlotProps) => Component &&
|
||||
wrapIf(Transition, route.meta.pageTransition ?? defaultPageTransition,
|
||||
wrapInKeepAlive(route.meta.keepalive, h(Suspense, {
|
||||
onPending: () => nuxtApp.callHook('page:start', Component),
|
||||
onResolve: () => nuxtApp.callHook('page:finish', Component)
|
||||
}, { default: () => h(Component) })
|
||||
)
|
||||
)
|
||||
)).default()
|
||||
}, { default: () => h(Component) }))).default()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const Fragment = {
|
||||
setup (props, { slots }) {
|
||||
return () => slots.default()
|
||||
}
|
||||
}
|
||||
|
||||
const wrapIf = (component: Component, props: any, slots: any) => {
|
||||
return { default: () => props ? h(component, props === true ? {} : props, slots) : h(Fragment, {}, slots) }
|
||||
}
|
||||
|
||||
const wrapInKeepAlive = (props: any, children: any) => {
|
||||
return { default: () => process.client && props ? h(KeepAlive, props === true ? {} : props, children) : children }
|
||||
}
|
||||
|
||||
const defaultLayoutTransition = { name: 'layout', mode: 'out-in' }
|
||||
const defaultPageTransition = { name: 'page', mode: 'out-in' }
|
||||
|
15
packages/nuxt3/src/pages/runtime/utils.ts
Normal file
15
packages/nuxt3/src/pages/runtime/utils.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Component, KeepAlive, h } from 'vue'
|
||||
|
||||
const Fragment = {
|
||||
setup (_props, { slots }) {
|
||||
return () => slots.default()
|
||||
}
|
||||
}
|
||||
|
||||
export const wrapIf = (component: Component, props: any, slots: any) => {
|
||||
return { default: () => props ? h(component, props === true ? {} : props, slots) : h(Fragment, {}, slots) }
|
||||
}
|
||||
|
||||
export const wrapInKeepAlive = (props: any, children: any) => {
|
||||
return { default: () => process.client && props ? h(KeepAlive, props === true ? {} : props, children) : children }
|
||||
}
|
Loading…
Reference in New Issue
Block a user