likes
comments
collection
share

Next.js 13 项目中的多布局使用方法,你应该要会

作者站长头像
站长
· 阅读数 18

一、需求讲解

在项目编写过程中,有可能会遇到这样的需求,在/app/demo01中需要有侧边栏,在同级目录下/app/demo02中不需要侧边栏,或者不需要侧边栏需要头部,这样的需求,我们就不能单单的靠一个Layout文件来使用。

1.1、/app/demo01(有侧边栏,没有header)

Next.js 13 项目中的多布局使用方法,你应该要会

1.2 /app/demo02(没有侧边栏,有header)

Next.js 13 项目中的多布局使用方法,你应该要会

1.3、/app/demo03(有侧边栏,有header)

Next.js 13 项目中的多布局使用方法,你应该要会

二、实现讲解

注意📢:本文主要以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布局

Next.js 13 项目中的多布局使用方法,你应该要会

但是如图所示,如果页面的上一级设置了Layout布局,则会在上一次布局的基础上再嵌套一个Layout布局

2.2.2、在NextJs13中支持在App目录下创建(name)以括号的形式命名的文件目录,该文件不会作为路由

如图所示

Next.js 13 项目中的多布局使用方法,你应该要会

当前目录下共有三个页面//demo03/demo04,所以在以括号括起来的文件夹将不会渲染为路由,相当于下图的路径

Next.js 13 项目中的多布局使用方法,你应该要会

回到正题,我们熟悉了上面两个新特性后,这样我们就会明白其实需要不同的Layout只需要有不同的带()的文件夹而已,带括号的文件夹虽然不会被渲染成路由,但是同样也是拥有和页面一样的目录组成,可以给()文件夹单独设置layout.tsxloading.tsx以及error.tsx文件夹,这样在()号目录文件夹下的全部具有就会有layout布局。

即我们需要实现开头说的需求,只需要设置不同的带()的文件夹即可实现

Next.js 13 项目中的多布局使用方法,你应该要会

代码实现如下

目录结构

丨-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或者需要AsiderHeader的布局效果。当让这也只是我的一己之见,我也是相当于初接触NextJs13的App全新布局,有什么地方有问题或者有其他的方案的,欢迎大家评论区讨论。

本文使用的代码已上传到github,地址github.com/izz520/Next…

我是YaSol,一个区块链行业的前端开发小菜鸡。