mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-26 23:52:06 +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>
|
<script setup>
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
function enableCustomLayout () {
|
function enableCustomLayout () {
|
||||||
// Note: because it's within a ref, it will persist if
|
route.meta.layout = "custom"
|
||||||
// you navigate away and then back to the page.
|
|
||||||
route.meta.layout.value = "custom"
|
|
||||||
}
|
}
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: ref(false),
|
layout: false,
|
||||||
});
|
});
|
||||||
</script>
|
</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 }) => {
|
nuxt.hook('prepare:types', ({ references }) => {
|
||||||
references.push({ path: resolve(nuxt.options.buildDir, 'middleware.d.ts') })
|
references.push({ path: resolve(nuxt.options.buildDir, 'middleware.d.ts') })
|
||||||
|
references.push({ path: resolve(nuxt.options.buildDir, 'layouts.d.ts') })
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add layouts template
|
// 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 type { Router, RouteLocationNormalizedLoaded, NavigationGuard, RouteLocationNormalized, RouteLocationRaw } from 'vue-router'
|
||||||
import { useNuxtApp } from '#app'
|
import { useNuxtApp } from '#app'
|
||||||
|
|
||||||
@ -14,13 +14,12 @@ export interface PageMeta {
|
|||||||
[key: string]: any
|
[key: string]: any
|
||||||
pageTransition?: false | TransitionProps
|
pageTransition?: false | TransitionProps
|
||||||
layoutTransition?: false | TransitionProps
|
layoutTransition?: false | TransitionProps
|
||||||
layout?: false | string | Ref<false | string> | ComputedRef<false | string>
|
|
||||||
key?: string | ((route: RouteLocationNormalizedLoaded) => string)
|
key?: string | ((route: RouteLocationNormalizedLoaded) => string)
|
||||||
keepalive?: false | KeepAliveProps
|
keepalive?: false | KeepAliveProps
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'vue-router' {
|
declare module 'vue-router' {
|
||||||
interface RouteMeta extends PageMeta {}
|
interface RouteMeta extends UnwrapRef<PageMeta> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const warnRuntimeUsage = (method: string) =>
|
const warnRuntimeUsage = (method: string) =>
|
||||||
|
@ -25,26 +25,34 @@ export default defineComponent({
|
|||||||
const hasLayout = props.layout ?? route.meta.layout ?? 'default' in layouts
|
const hasLayout = props.layout ?? route.meta.layout ?? 'default' in layouts
|
||||||
|
|
||||||
return h(RouterView, {}, {
|
return h(RouterView, {}, {
|
||||||
default: ({ Component }: RouterViewSlotProps) => Component && wrapIf(Transition, hasLayout && (route.meta.layoutTransition ?? defaultLayoutTransition), {
|
default: ({ Component }: RouterViewSlotProps) => Component &&
|
||||||
default: () => wrapIf(NuxtLayout, hasLayout && { layout: props.layout ?? route.meta.layout }, {
|
wrapIf(Transition, hasLayout && (route.meta.layoutTransition ?? defaultLayoutTransition),
|
||||||
default: () => wrapIf(Transition, route.meta.pageTransition ?? defaultPageTransition, {
|
wrapIf(NuxtLayout, hasLayout && { name: props.layout ?? route.meta.layout },
|
||||||
default: () => wrapIf(KeepAlive, process.client && route.meta.keepalive, h(Suspense, {
|
wrapIf(Transition, route.meta.pageTransition ?? defaultPageTransition,
|
||||||
|
wrapInKeepAlive(route.meta.keepalive, h(Suspense, {
|
||||||
onPending: () => nuxtApp.callHook('page:start', Component),
|
onPending: () => nuxtApp.callHook('page:start', Component),
|
||||||
onResolve: () => nuxtApp.callHook('page:finish', Component)
|
onResolve: () => nuxtApp.callHook('page:finish', Component)
|
||||||
}, { default: () => h(Component) }))
|
}, { default: () => h(Component) })
|
||||||
})
|
)
|
||||||
})
|
)
|
||||||
})
|
)).default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const wrapIf = (component: Component, props: any, slotsOrChildren: any) => {
|
const Fragment = {
|
||||||
if (props) {
|
setup (props, { slots }) {
|
||||||
return h(component, props === true ? {} : props, slotsOrChildren)
|
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' }
|
const defaultLayoutTransition = { name: 'layout', mode: 'out-in' }
|
||||||
|
@ -66,6 +66,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
router.beforeEach(async (to, from) => {
|
router.beforeEach(async (to, from) => {
|
||||||
|
to.meta = reactive(to.meta)
|
||||||
nuxtApp._processingMiddleware = true
|
nuxtApp._processingMiddleware = true
|
||||||
|
|
||||||
type MiddlewareDef = string | NavigationGuard
|
type MiddlewareDef = string | NavigationGuard
|
||||||
|
Loading…
Reference in New Issue
Block a user