Next.js 13 项目中的多布局使用方法,你应该要会
一、需求讲解
在项目编写过程中,有可能会遇到这样的需求,在/app/demo01
中需要有侧边栏,在同级目录下/app/demo02
中不需要侧边栏,或者不需要侧边栏需要头部,这样的需求,我们就不能单单的靠一个Layout文件来使用。
1.1、/app/demo01
(有侧边栏,没有header)
1.2 /app/demo02
(没有侧边栏,有header)
1.3、/app/demo03
(有侧边栏,有header)
二、实现讲解
注意📢:本文主要以NextJs为主,所以讲解的是NextJs的实现
2.1、NextJs12的实现方式
本文主要以NextJs13
为主,所以NextJs12
只是略微带过。
首先在NextJs12以前,我们可以实现类似的需求,但是相对来说比较麻烦,因为是嵌套的,相当于你需要侧边栏,那么被侧边栏的Layout包裹的所有页面都会有有这个侧边栏,如果某个页面不需要这个侧边栏只能通过js去控制侧边栏的显示。
大概得实现方式:
在Layout组件中,同时写<Asider/>
和<Header/>
,通过监听路由的变化去指定显示,例如指定/app/demo01
只显示<Asider/>
NextJs12简单实现如下
import { useRouter } from 'next/router'
import React, { memo, useEffect, useMemo, useState } from 'react'
const AsiderAndHeaderLayout = ({ children }: { children: React.ReactNode }) => {
const router = useRouter()
const [isShowAside, setIsShowAside] = useState<boolean>(true)
const [isShowHeader, setIsShowHeader] = useState<boolean>(true)
const asidePaths = ["/app/demo01"]
const headerPaths = ["/app/demo02"]
const asiderAndHeaderPaths = ["/app/demo03"]
useEffect(() => {
const path = router.pathname;
if (asidePaths.includes(path)) {
setIsShowAside(true)
} else if (headerPaths.includes(path)) {
setIsShowHeader(true)
} else if (asiderAndHeaderPaths.includes(path)) {
setIsShowAside(true)
setIsShowHeader(true)
}
}, [router])
const ContainerHeight = useMemo(() => {
return isShowHeader ? "h-[calc(100vh-60px)]" : "h-screen"
}, [isShowHeader])
return (
<div className='w-full h-screen flex flex-col'>
{isShowHeader && <div className='w-full h-[60px] bg-green-500'>Header</div>}
<div className={`w-full flex ${ContainerHeight}`}>
{isShowAside && <div className='flex-[320px_0_0] bg-blue-300'>Aside</div>}
<div className='flex-1'>{children}</div>
</div>
</div>
)
}
export default memo(AsiderAndHeaderLayout)
2.2、NextJs13的实现方式
在使用NextJs13
的方法之前,我们需要先了解NextJs13
的两个新特性
2.2.1、在NextJs13
的App目录下,每个页面都有一个Layout.tsx
的布局文件,但是不需要每个页面都设置,如果页面文件夹下有Layout.tsx
文件才会走页面的Layout
布局
但是如图所示,如果页面的上一级设置了Layout
布局,则会在上一次布局的基础上再嵌套一个Layout
布局
2.2.2、在NextJs13
中支持在App目录下创建(name)
以括号的形式命名的文件目录,该文件不会作为路由
如图所示
当前目录下共有三个页面/
、/demo03
、/demo04
,所以在以括号括起来的文件夹将不会渲染为路由,相当于下图的路径
回到正题,我们熟悉了上面两个新特性后,这样我们就会明白其实需要不同的Layout
只需要有不同的带()
的文件夹而已,带括号的文件夹虽然不会被渲染成路由,但是同样也是拥有和页面一样的目录组成,可以给()
文件夹单独设置layout.tsx
和loading.tsx
以及error.tsx
文件夹,这样在()
号目录文件夹下的全部具有就会有layout
布局。
即我们需要实现开头说的需求,只需要设置不同的带()
的文件夹即可实现
代码实现如下
目录结构
丨-app
丨--(asider) ---只显示侧边栏布局
丨----layout.tsx
丨----demo01
丨——————page.tsx
丨--(header)---只显示Header布局
丨----layout.tsx
丨----demo02
丨------page.tsx
丨--(asiderAndHeader)---显示侧边栏布局和Header布局
丨----layout.tsx
丨----demo03
丨------page.tsx
// (asider)的Layout.tsx
import React from 'react'
const layout = ({ children }: { children: React.ReactNode }) => {
return (
<div className='w-full h-screen flex'>
<div className='flex-[327px_0_0] bg-gray-500 text-white'>aside</div>
<div className='flex-1'>
{children}
</div>
</div>
)
}
export default layout
// (header)的Layout.tsx
import React from 'react'
const HeaderLayout = ({ children }: { children: React.ReactNode }) => {
return (
<div className='w-full h-screen flex flex-col'>
<div className='flex-[70px_0_0] bg-gray-500 text-white'>Header</div>
<div className='flex-1'>{children}</div>
</div>
)
}
export default HeaderLayout
// (asiderAndHeader)的Layout.tsx
import React, { memo } from 'react'
const AsiderAndHeaderLayout = ({children}:{children:React.ReactNode}) => {
return (
<div className='w-full h-screen flex flex-col'>
<div className='w-full h-[60px] bg-green-500'>Header</div>
<div className='w-full h-[calc(100vh-60px)] flex'>
<div className='flex-[320px_0_0] bg-orange-300'>Aside</div>
<div className='flex-1'>{children}</div>
</div>
</div>
)
}
export default memo(AsiderAndHeaderLayout)
总结
通过上面的代码,我们就可以很容易的实现需要Aside
或者需要Header
或者需要Asider
和Header
的布局效果。当让这也只是我的一己之见,我也是相当于初接触NextJs13
的App全新布局,有什么地方有问题或者有其他的方案的,欢迎大家评论区讨论。
本文使用的代码已上传到github,地址github.com/izz520/Next…
我是YaSol,一个区块链行业的前端开发小菜鸡。
转载自:https://juejin.cn/post/7247058712194695224