mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 21:55:11 +00:00
feat(nuxt3): make layout and other page meta reactive (#2926)
This commit is contained in:
parent
696138794b
commit
944464781d
@ -79,12 +79,10 @@ You can also use a ref or computed property for your layout.
|
||||
<script setup>
|
||||
const route = useRoute()
|
||||
function enableCustomLayout () {
|
||||
// Note: because it's within a ref, it will persist if
|
||||
// you navigate away and then back to the page.
|
||||
route.meta.layout.value = "custom"
|
||||
route.meta.layout = "custom"
|
||||
}
|
||||
definePageMeta({
|
||||
layout: ref(false),
|
||||
layout: false,
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
@ -112,8 +112,27 @@ export default defineNuxtModule({
|
||||
}
|
||||
})
|
||||
|
||||
addTemplate({
|
||||
filename: 'layouts.d.ts',
|
||||
write: true,
|
||||
getContents: async () => {
|
||||
const composablesFile = resolve(runtimeDir, 'composables')
|
||||
const layouts = await resolveLayouts(nuxt)
|
||||
return [
|
||||
'import { ComputedRef, Ref } from \'vue\'',
|
||||
`export type LayoutKey = ${layouts.map(layout => `"${layout.name}"`).join(' | ') || 'string'}`,
|
||||
`declare module '${composablesFile}' {`,
|
||||
' interface PageMeta {',
|
||||
' layout?: false | LayoutKey | Ref<LayoutKey> | ComputedRef<LayoutKey>',
|
||||
' }',
|
||||
'}'
|
||||
].join('\n')
|
||||
}
|
||||
})
|
||||
|
||||
nuxt.hook('prepare:types', ({ references }) => {
|
||||
references.push({ path: resolve(nuxt.options.buildDir, 'middleware.d.ts') })
|
||||
references.push({ path: resolve(nuxt.options.buildDir, 'layouts.d.ts') })
|
||||
})
|
||||
|
||||
// Add layouts template
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ComputedRef, KeepAliveProps, Ref, TransitionProps } from 'vue'
|
||||
import { KeepAliveProps, TransitionProps, UnwrapRef } from 'vue'
|
||||
import type { Router, RouteLocationNormalizedLoaded, NavigationGuard, RouteLocationNormalized, RouteLocationRaw } from 'vue-router'
|
||||
import { useNuxtApp } from '#app'
|
||||
|
||||
@ -14,13 +14,12 @@ export interface PageMeta {
|
||||
[key: string]: any
|
||||
pageTransition?: false | TransitionProps
|
||||
layoutTransition?: false | TransitionProps
|
||||
layout?: false | string | Ref<false | string> | ComputedRef<false | string>
|
||||
key?: string | ((route: RouteLocationNormalizedLoaded) => string)
|
||||
keepalive?: false | KeepAliveProps
|
||||
}
|
||||
|
||||
declare module 'vue-router' {
|
||||
interface RouteMeta extends PageMeta {}
|
||||
interface RouteMeta extends UnwrapRef<PageMeta> {}
|
||||
}
|
||||
|
||||
const warnRuntimeUsage = (method: string) =>
|
||||
|
@ -25,26 +25,34 @@ export default defineComponent({
|
||||
const hasLayout = props.layout ?? route.meta.layout ?? 'default' in layouts
|
||||
|
||||
return h(RouterView, {}, {
|
||||
default: ({ Component }: RouterViewSlotProps) => Component && wrapIf(Transition, hasLayout && (route.meta.layoutTransition ?? defaultLayoutTransition), {
|
||||
default: () => wrapIf(NuxtLayout, hasLayout && { layout: props.layout ?? route.meta.layout }, {
|
||||
default: () => wrapIf(Transition, route.meta.pageTransition ?? defaultPageTransition, {
|
||||
default: () => wrapIf(KeepAlive, process.client && route.meta.keepalive, h(Suspense, {
|
||||
default: ({ Component }: RouterViewSlotProps) => Component &&
|
||||
wrapIf(Transition, hasLayout && (route.meta.layoutTransition ?? defaultLayoutTransition),
|
||||
wrapIf(NuxtLayout, hasLayout && { name: props.layout ?? route.meta.layout },
|
||||
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: () => h(Component) })
|
||||
)
|
||||
)
|
||||
)).default()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const wrapIf = (component: Component, props: any, slotsOrChildren: any) => {
|
||||
if (props) {
|
||||
return h(component, props === true ? {} : props, slotsOrChildren)
|
||||
const Fragment = {
|
||||
setup (props, { slots }) {
|
||||
return () => slots.default()
|
||||
}
|
||||
return slotsOrChildren.default?.() || slotsOrChildren
|
||||
}
|
||||
|
||||
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' }
|
||||
|
@ -66,6 +66,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||
}
|
||||
|
||||
router.beforeEach(async (to, from) => {
|
||||
to.meta = reactive(to.meta)
|
||||
nuxtApp._processingMiddleware = true
|
||||
|
||||
type MiddlewareDef = string | NavigationGuard
|
||||
|
Loading…
Reference in New Issue
Block a user