Next.js 实战 (七):浅谈 Layout 布局的嵌套设计模式

业务场景

在目前常见的中后台管理系统中,比较常见的是固定的布局方式包裹页面,但一些特殊页面,比如:登录页面注册页面忘记密码页面这些页面是不需要布局包裹的。

但在 Next.js AppRouter 中,必须包含一个根布局文件(RootLayout),默认情况下,文件夹层次结构中的布局也是嵌套的,这意味着它们通过其子布局的属性来包装子布局。这是 Next.js 框架的设计理念,目的是允许你创建复杂的页面结构,同时保持代码的整洁和可维护性。

以官网 Nesting layouts 为例,最后 app/blog/[slug]/page.js 生成的结果为:

<RootLayout><BlogLayout>{children}</BlogLayout>
</RootLayout>

正常页面是这样的:
在这里插入图片描述

但登录页面如果不处理就会变成这样:
在这里插入图片描述

很明显,这不是我们想要的,我们希望这些特殊页面不需要父级 layout 包裹,那这个问题该怎么去解决呢?

解决方案

我在网上几乎找不到关于 Next.js layout 嵌套布局 的资料,但我觉得这个问题挺有意思的,所以特地写篇文章讨论一下。

这个问题归根结底就是你要不要在 RootLayout 里面写入布局代码,这时候就会分两种情况:

  1. 如果你不嫌麻烦,RootLayout 根布局留空,然后在需要的页面下都新建一个 layout.tsx 文件:
export default async function RootLayout({children,
}: Readonly<{children: React.ReactNode;
}>) {return (<html lang={locale} suppressHydrationWarning><body>{children}</body></html>);
}

我看一些 Next.js 教程的源码就是这样布局的,感觉有点麻烦。

  1. 还有一种就是默认 RootLayout 是常规布局,我们需要想个办法在一些特殊页面把 RootLayout 包裹去掉。

我采用的是后者,确定方案后,决定结合 zustand 来定义一个变量用来是否显示根布局。

具体步骤

  1. 新建 /store/layoutStore.ts 文件:
import { create } from 'zustand';type LayoutState = {skipGlobalLayout: boolean;setSkipGlobalLayout: (skip: boolean) => void;
};export const useLayoutStore = create<LayoutState>((set) => ({skipGlobalLayout: false,setSkipGlobalLayout: (skip) => set({ skipGlobalLayout: skip }),
}));
  1. 新建 /components/GlobalLayout 文件:
'use client';
import { SessionProvider } from 'next-auth/react';import AppSideBar from '@/components/AppSideBar';
import GlobalFooter from '@/components/GlobalFooter'; // 底部版权
import GlobalHeader from '@/components/GlobalHeader'; // 头部布局
import PageAnimatePresence from '@/components/PageAnimatePresence';
import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar';
import { useLayoutStore } from '@/store/layoutStore';type GlobalLayoutProps = {children: React.ReactNode;
};export default function GlobalLayout({ children }: GlobalLayoutProps) {// 是否跳过全局布局const skipGlobalLayout = useLayoutStore((state) => state.skipGlobalLayout);return skipGlobalLayout ? (<>{children}</>) : (<SessionProvider><SidebarProvider><AppSideBar /><SidebarInset>{/* 头部布局 */}<GlobalHeader /><PageAnimatePresence>{children}</PageAnimatePresence>{/* 底部版权 */}<GlobalFooter /></SidebarInset></SidebarProvider></SessionProvider>);
}
  1. 修改根目录 layout.tsx 文件:
import GlobalLayout from '@/components/GlobalLayout'; // 全局布局export default async function RootLayout({children,
}: Readonly<{children: React.ReactNode;
}>) {return (<html lang={locale} suppressHydrationWarning><body><GlobalLayout>{children}</GlobalLayout></body></html>);
}
  1. 在不需要 RootLayout 的页面 layout.tsx 文件中:
'use client';import { useMount, useUnmount } from 'ahooks';import LangSwitch from '@/components/LangSwitch';
import ThemeModeButton from '@/components/ThemeModeButton';
import { useLayoutStore } from '@/store/layoutStore';export default function LoginLayout({ children }: { children: React.ReactNode }) {useMount(() => {useLayoutStore.setState({ skipGlobalLayout: true });});useUnmount(() => {// 如果需要在离开页面时重置状态useLayoutStore.setState({ skipGlobalLayout: false });});return (<div className="relative flex h-[calc(100vh_-_2rem)] w-[calc(100vw_-_2rem)] overflow-hidden justify-center items-center">{children}<div className="flex absolute top-0 right-0"><ThemeModeButton /><LangSwitch /></div></div>);
}

我们根据 skipGlobalLayout 属性来判断是否显示 RootLayout 布局,这样就能达到我们的目的了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/67858.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于 Python 和 OpenCV 的人脸识别上课考勤管理系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

PHP语言的函数实现

PHP语言的函数实现 在现代Web开发中&#xff0c;PHP是一种流行的后端脚本语言。它以简单易学和强大的功能著称&#xff0c;广泛应用于构建动态网站和Web应用程序。在PHP中&#xff0c;函数是组织代码、提高代码重用性和可读性的关键元素。本文将深入探讨PHP的函数实现&#xf…

人工智能与物联网:智慧城市的未来

引言 清晨6点&#xff0c;智能闹钟根据你的睡眠状态和天气情况&#xff0c;自动调整叫醒时间&#xff1b;窗帘缓缓打开&#xff0c;阳光洒满房间&#xff1b;厨房里的咖啡机已经为你准备好热饮&#xff0c;而无人驾驶公交车正按时抵达楼下站点。这不是科幻电影的场景&#xff…

小R的蛋糕分享

小R的蛋糕分享 问题描述 小R手里有一个大小为 n 行 m 列的矩形蛋糕&#xff0c;每个小正方形区域都有一个代表美味度的整数。小R打算切割出一个正方形的小蛋糕给自己&#xff0c;而剩下的部分将给小S。她希望两人吃的部分的美味度之和尽量接近。 我们定义小R吃到的部分的美味度…

使用postMessage解决iframe与父页面传参

接收传递的消息时&#xff0c;可以将 window.addEventListener(message, function(e) { console.log(e.data) }) 写法&#xff0c;更换为 window.onmessage async function(e) {} 可以避免消息发送后&#xff0c;多次接收该参数 父页面js IframeEvent(){const send …

python-leetcode-无重复字符的最长子串

3. 无重复字符的最长子串 - 力扣&#xff08;LeetCode&#xff09; class Solution:def lengthOfLongestSubstring(self, s: str) -> int:char_set set()left 0max_length 0for right in range(len(s)):while s[right] in char_set:char_set.remove(s[left])left 1char_…

新版本的IDEA如何解决Git分支显示为警告⚠<unknown>的问题

目录 问题再现 解决思路 首先我们要想到 这个分支有没有从远程代码仓库拉去下来 复习一下 git 命令 其次思考 最后思考 问题再现 这边我使用的是 IDEA 2024.3.3.1 Jetbrains 官网的最新版 同时也是官方账号登录 的 今天上 github 去拉项目到 本地 出现了分支不显示的问…

libusb学习——简单介绍

文章目录 libusb 简介libusb 编译libusb 源码目录介绍核心代码文件平台支持例子 API使用libusb初始化和去初始化libusb设备处理和枚举libusb 杂项libusb USB描述符libusb 设备热插拔事件通知libusb 异步设备I/Olibusb 同步设备I/Olibusb 轮询与定时 libusb 涉及技术参考 libusb…

GRE技术的详细解释

GRE&#xff08;Generic Routing Encapsulation&#xff0c;通用路由封装&#xff09;是一种隧道协议&#xff0c;主要用于在不同网络之间封装和传输其他网络层协议的数据包。它最常用于在IP网络上建立虚拟点到点的隧道连接&#xff0c;是实现VPN的一项关键技术。 下面从原理、…

HarmonyOS 鸿蒙Next 预览pdf文件

HarmonyOS 鸿蒙Next 预览pdf文件 1、使用filePreview 2、使用web组件 在线pdf&#xff08;网址是直接下载的&#xff0c;不是直接可以预览的&#xff09;&#xff0c;先下载再预览 import media from ohos.multimedia.media;import web_webview from ohos.web.webview;import …

案例解读 | 香港某多元化综合金融企业基础监控+网管平台建设实践

PART01 项目背景 01客户简介案例客户是一家创立20多年的香港某多元化综合金融企业&#xff0c;其业务范围涵盖证券、期货、资产管理、财富管理等&#xff0c;凭借广泛的业务网络和多元化的金融服务产品&#xff0c;在市场中拥有显著的影响力。02痛点分析随着业务版图的持续拓展…

551 灌溉

常规解法&#xff1a; #include<bits/stdc.h> using namespace std; int n,m,k,t; const int N105; bool a[N][N],b[N][N]; int cnt; //设置滚动数组来存贮当前和下一状态的条件 //处理传播扩散问题非常有效int main() {cin>>n>>m>>t;for(int i1;i&l…

vue的KeepAlive应用(针对全部页面及单一页面进行缓存)

KeepAlive的作用是缓存包裹在其中的动态切换组件 当一个组件在 中被切换时&#xff0c;它的 activated 和 deactivated 生命周期钩子将被调用&#xff0c;用来替代 mounted 和 unmounted。这适用于 的直接子节点及其所有子孙节点。 缓存全部页面 将app.vue中的路由出口改为&am…

【简博士统计学习方法】第1章:4. 模型的评估与选择

4. 模型的评估与选择 4.1 训练误差与测试误差 假如存在样本容量为 N N N的训练集&#xff0c;将训练集送入学习系统可以训练学习得到一个模型&#xff0c;我们将这么模型用决策函数的形式表达&#xff0c;也就是 y f ^ ( x ) y\hat{f}(x) yf^​(x)&#xff0c;关于模型的拟合…

Lua语言的文件IO

1、我们都知道&#xff0c;在任何语言当中都有输入输出&#xff0c;比如c语言当中就有很多printf,scanf,get ,put,gets,puts,文件io:open,read,write,close,标准io:fopen,fread,fwrite,fclose.在lua语言当中&#xff0c;也有相同的一些输入输出特性&#xff0c;叫io.open,io.re…

关于智能个人生活助手的一些想法

我感觉未来计算机发展 会变成钢铁侠的贾维斯那样, 每个人有自己的系统 集成ai和其他功能 助力生活和工作 说一下我为什么有这样的想法: 1.ai发展迅猛: 近些年来ai的发展势头越来越猛,不断破圈,越来越多的人了解到ai的强大,并使用ai改变了自己原有的生活或工作方式,熟练使用…

【css】浏览器强制设置元素状态(hover|focus……)

直接上步骤&#xff1a; 打开浏览器控制台 → 找到样式选项 → 找到:hov选项 → 点击:hov选项&#xff0c;会展开【设置元素状态】。 只要选中就会展示出自己写在css里面的该种状态下的样式了。

Erlang语言的文件操作

Erlang语言的文件操作 引言 Erlang是一种并发编程语言&#xff0c;最初由爱立信为开发电信系统而设计&#xff0c;其后逐渐被广泛应用于分布式、实时系统等场景。虽然Erlang以其强大的并发和容错能力著称&#xff0c;但在日常开发中&#xff0c;文件操作也是一个非常重要的部…

第26章 汇编语言--- 内核态与用户态

汇编语言是低级编程语言的一种&#xff0c;它与特定计算机的硬件架构紧密相关。内核态和用户态是操作系统中进程运行的两种不同模式&#xff0c;它们用来区分操作系统内核代码和其他应用程序代码的执行环境。下面我将简要解释这两种状态&#xff0c;并给出一个简单的示例来展示…

LabVIEW水轮发电机组振动摆度故障诊断

本文介绍了基于LabVIEW的水轮发电机组振动摆度故障诊断系统的设计与实施过程。系统在通过高效的故障诊断功能&#xff0c;实现水轮发电机组的振动、温度等关键指标的实时监控与智能分析&#xff0c;从而提高电力设备的可靠性和安全性。 ​ 项目背景 随着电力行业对设备稳定性…