Material UI Sign-up 模板实战:从复制到完全定制注册页面的完整指南
【免费下载链接】material-uiMaterial UI: Comprehensive React component library that implements Google's Material Design. Free forever.项目地址: https://gitcode.com/GitHub_Trending/ma/material-ui
Material UI 官方提供了一套免费 React 模板,其中 Sign-up(注册页)模板是构建用户注册流程的起点。本文基于仓库中的 Sign-up 模板说明文档 及其完整源码,讲清模板的文件构成、三步接入流程、SignUp组件内部的表单校验与主题体系,以及如何通过shared-theme目录对品牌色、明暗模式与组件样式进行定制,读完即可将模板落地到自己的项目并改造为符合业务需求的注册页面。
一、Sign-up 模板的定位
模板位于docs/data/material/getting-started/templates/sign-up/目录,与 dashboard、marketing-page、checkout、sign-in、sign-in-side、blog 等模板共同组成免费模板集合(见 templates.md)。官方文档说明这些模板均内置“自定义主题 + 默认 Material Design 2 主题”,并各自支持 light/dark 两种模式。
Sign-up 模板的目录结构非常小,由三部分构成:
docs/data/material/getting-started/templates/ ├── sign-up/ │ ├── SignUp.tsx / SignUp.js # 注册页主组件 │ ├── components/ │ │ ├── CustomIcons.tsx / .js # Sitemark、Google、Facebook 图标 │ │ └── ... │ └── README.md # 使用说明(本文核心文档) └── shared-theme/ # 所有模板共享的主题代码 ├── AppTheme.tsx / .js # ThemeProvider 封装 ├── ColorModeSelect.tsx / .js # 明暗模式切换器 ├── themePrimitives.ts / .js # 色板、字体、圆角、阴影等设计令牌 └── customizations/ # inputs / dataDisplay / feedback / navigation / surfaces 组件定制每个模板都提供.tsx(TypeScript)和.js(JavaScript)两个版本,可按项目语言选择其一复制,未使用的版本可直接忽略。
二、三步接入流程(官方用法)
README 给出的官方接入步骤为:
- 将
sign-up与shared-theme两个文件夹复制进你的项目(或官方示例项目); - 确保项目安装了必要依赖:
@mui/material、@mui/icons-material、@emotion/styled、@emotion/react; - 导入并使用
SignUp组件。
以官方 Next.js 示例项目 examples/material-ui-nextjs 的package.json为参考,一个典型项目的依赖声明大致如下:
{ "dependencies": { "@emotion/cache": "latest", "@emotion/react": "latest", "@emotion/styled": "latest", "@mui/icons-material": "latest", "@mui/material": "latest", "@mui/material-nextjs": "latest", "next": "^16.0.7", "react": "^19.0.0", "react-dom": "^19.0.0" } }其中 README 列出的四个依赖之外,示例项目还引入了@emotion/cache(SSR 场景的 Emotion 缓存)与@mui/material-nextjs(Next.js 专用适配层)——如果你在 Next.js App Router 中使用模板,建议一并安装。
接入后的使用方式即:
import SignUp from './sign-up/SignUp'; export default function App() { return <SignUp />; }SignUp组件接受一个可选的disableCustomTheme?: boolean属性,该属性是文档站点渲染预览时使用的开关(源码注释明确写着 “This is for the docs site. You can ignore it or remove it.”),在自己的项目中可以忽略它。
三、SignUp 组件源码详解
主组件在 SignUp.tsx 中,共约 230 行,可拆为四个部分:主题包裹、页面容器、表单与校验、社交登录区。
3.1 主题包裹与明暗模式切换
组件的返回结构是:
return ( <AppTheme {...props}> <CssBaseline enableColorScheme /> <ColorModeSelect sx={{ position: 'fixed', top: '1rem', right: '1rem' }} /> <SignUpContainer direction="column" sx={{ justifyContent: 'space-between' }}> <Card variant="outlined"> {/* ...页面内容... */} </Card> </SignUpContainer> </AppTheme> );AppTheme(shared-theme/AppTheme.tsx)是模板的主题入口,内部用React.useMemo创建主题并注入ThemeProvider,且设置了disableTransitionOnChange避免切换模式时样式闪动;CssBaseline配合enableColorScheme使全局 CSS 变量随 color scheme 切换;ColorModeSelect(shared-theme/ColorModeSelect.tsx)是一个固定在右上角的Select,基于 MUI 的useColorSchemehook 提供 System / Light / Dark 三档切换。
useColorScheme只有在主题配置了colorSchemes时才会返回有效的mode/setMode,这正是模板主题支持明暗切换的底层机制(下一节展开)。
3.2 页面容器:SignUpContainer与Card
模板用styled定义了两个布局组件,是页面视觉效果的来源:
const Card = styled(MuiCard)(({ theme }) => ({ display: 'flex', flexDirection: 'column', alignSelf: 'center', width: '100%', padding: theme.spacing(4), gap: theme.spacing(2), margin: 'auto', boxShadow: 'hsla(220, 30%, 5%, 0.05) 0px 15px 35px -5px, ...', [theme.breakpoints.up('sm')]: { width: '450px', // sm 断点以上固定 450px 宽 }, ...theme.applyStyles('dark', { boxShadow: /* 深色模式加深的阴影 */, }), }));const SignUpContainer = styled(Stack)(({ theme }) => ({ height: 'calc((1 - var(--template-frame-height, 0)) * 100dvh)', minHeight: '100%', padding: theme.spacing(2), [theme.breakpoints.up('sm')]: { padding: theme.spacing(4) }, '&::before': { content: '""', display: 'block', position: 'absolute', zIndex: -1, inset: 0, backgroundImage: 'radial-gradient(ellipse at 50% 50%, hsl(210, 100%, 97%), hsl(0, 0%, 100%))', backgroundRepeat: 'no-repeat', ...theme.applyStyles('dark', { backgroundImage: 'radial-gradient(at 50% 50%, hsla(210, 100%, 16%, 0.5), hsl(220, 30%, 5%))', }), }, }));两个值得注意的实现细节:
- CSS 变量占位:
height使用了var(--template-frame-height, 0),该变量由文档站点的预览框架注入,用于给演示边框留出高度;在自己的项目中回退值为0,因此容器高度等价于100dvh,可放心保留。注意--template前缀来自主题配置中的cssVarPrefix: 'template'(见 AppTheme.tsx)。 - 深色模式写法:所有深色样式都通过
theme.applyStyles('dark', {...})注入,这是 Material UI v6 起推荐的 CSS 变量方案写法,替代了旧版theme.palette.mode === 'dark'的三元判断。
3.3 表单字段与校验逻辑
模板内置了三组 React 状态驱动的错误展示(每个字段一对xxxError+xxxErrorMessage状态):
const [emailError, setEmailError] = React.useState(false); const [emailErrorMessage, setEmailErrorMessage] = React.useState(''); const [passwordError, setPasswordError] = React.useState(false); // name 字段同理提交前由validateInputs完成客户端校验:
const validateInputs = () => { const email = document.getElementById('email') as HTMLInputElement; const password = document.getElementById('password') as HTMLInputElement; const name = document.getElementById('name') as HTMLInputElement; let isValid = true; if (!email.value || !/\S+@\S+\.\S+/.test(email.value)) { setEmailError(true); setEmailErrorMessage('Please enter a valid email address.'); isValid = false; } else { /* 清除错误 */ } if (!password.value || password.value.length < 6) { setPasswordError(true); setPasswordErrorMessage('Password must be at least 6 characters long.'); isValid = false; } else { /* 清除错误 */ } if (!name.value || name.value.length < 1) { /* 姓名必填 */ } return isValid; };校验规则一览:
| 字段 | 规则 | 错误提示 |
|---|---|---|
Full name(name) | 非空 | Name is required. |
Email(email) | 非空且匹配/\S+@\S+\.\S+/ | Please enter a valid email address. |
Password(password) | 非空且长度 ≥ 6 | Password must be at least 6 characters long. |
每个字段的TextField通过error、helperText、color三个 prop 与上述状态联动,例如:
<TextField autoComplete="email" name="email" required fullWidth id="email" placeholder="your@email.com" error={emailError} helperText={emailErrorMessage} color={passwordError ? 'error' : 'primary'} />两处可以直接从源码发现的问题,落地时建议顺手修正:
- email 字段的
color误引用了passwordError(见 SignUp.tsx),从源码结构看这应为emailError,当前写法会导致密码错误时邮箱输入框边框也变红,而邮箱自身错误时颜色不变; handleSubmit中读取了不存在的lastName字段:console.log({ ..., lastName: data.get('lastName'), ... })(见 SignUp.tsx),但页面上并没有name="lastName"的输入框,该值恒为null。表单提交本身也只是console.log演示,真实项目需替换为对后端接口的请求。
表单交互流程为:Button type="submit"的onClick触发validateInputs,校验失败时handleSubmit检测到任一错误状态为true便preventDefault()中止提交。三个输入框都设置了autoComplete(name/email/new-password),有利于浏览器密码管理器识别。此外还有一个Checkbox(“I want to receive updates via email.”)作为可选项演示,其外观由主题的MuiCheckbox定制样式接管。
3.4 社交登录区与登录跳转
表单下方的<Divider>or</Divider>分隔出社交注册区:
<Button fullWidth variant="outlined" onClick={() => alert('Sign up with Google')} startIcon={<GoogleIcon />} > Sign up with Google </Button>Google 与 Facebook 按钮目前只是alert占位,接入 OAuth 时把onClick替换为跳转授权地址即可。GoogleIcon、FacebookIcon与SitemarkIcon定义在 components/CustomIcons.tsx 中,均以SvgIcon包裹内联 SVG 实现(Facebook 图标使用#1AAFFF → #0163E0线性渐变,Google 图标使用四色官方配色),不依赖@mui/icons-material的固定图标集,方便替换成任意品牌图形。
页面底部提供跳转到 Sign-in 模板的Link(“Already have an account? Sign in”)。在文档站点中它指向 sign-in 模板的预览页;在自己的项目中应改成你应用内部的路由(例如配合next/link或 react-router 的Link)。
四、shared-theme:模板的设计令牌与组件定制
模板的视觉一致性由 shared-theme 目录保障,这也是复制模板时“必须连同复制”的原因。
4.1 设计令牌:themePrimitives
themePrimitives.ts 导出四个核心对象:
- 色板:
brand(主色,蓝色系,hsl(210, 100%, 42%)附近为主)、gray、green、orange、red,均为 50–900 的 HSL 十级色阶。改品牌色只需替换brand色阶,模板内所有引用都会随之更新; colorSchemes:以 Material UI v6 的 color schemes API 分别声明light与dark两套 palette(primary/info/warning/error/success/grey/background/text/action/divider),这是useColorScheme能切换明暗模式的前提;typography:字体Inter, sans-serif,h1 48px、h4 24px、body1/2 14px、caption 12px 等一整套字号与字重;shape与shadows:全局圆角borderRadius: 8;阴影数组第 2 位被替换为 CSS 变量var(--template-palette-baseShadow),配合各模式下的baseShadow令牌实现阴影随明暗模式变化。
文件头部还通过declare module扩展了Palette(新增baseShadow)与PaletteColor(要求完整 50–900 色阶)的类型,保证色板修改时的类型安全。
4.2 AppTheme 的主题装配
AppTheme.tsx 中的关键配置:
createTheme({ cssVariables: { colorSchemeSelector: 'data-mui-color-scheme', cssVarPrefix: 'template', }, colorSchemes, typography, shadows, shape, components: { ...inputsCustomizations, ...dataDisplayCustomizations, ...feedbackCustomizations, ...navigationCustomizations, ...surfacesCustomizations, ...themeComponents, }, });cssVarPrefix: 'template'决定了所有 CSS 变量以--template-开头(例如--template-frame-height、--template-palette-baseShadow),如果同时使用多个模板主题需改为不冲突的前缀;colorSchemeSelector: 'data-mui-color-scheme'指明模式切换作用于哪个 data 属性;themeComponents属性允许调用方追加/覆盖组件样式,即在不改动模板源码的前提下做局部定制。
4.3 组件定制:customizations 五模块
customizations/下按组件域拆成五个文件(inputs.tsx、dataDisplay.tsx、feedback.tsx、navigation.tsx、surfaces.ts),分别覆盖表单控件、数据展示、反馈、导航、表面(Paper/Card/Accordion 等)。与 Sign-up 页面直接相关的两处:
- surfaces.ts 中的
MuiCard:注册页的<Card variant="outlined">正是命中这里的outlinedvariant 定制——白底(深色模式为alpha(gray[900], 0.4))、1px divider 边框、boxShadow: 'none',卡片自身的双层柔和阴影则由SignUp.tsx里的styled(Card)叠加; - inputs.tsx 中的
MuiButton/MuiOutlinedInput/MuiCheckbox:按钮去阴影、textTransform: 'none'、按 variant 定义 hover/active 渐变;OutlinedInput聚焦时显示3px solid alpha(brand[500], 0.5)的 outline 而非默认 border 加粗;Checkbox换用 rounded 图标并压缩为 16px——注册表单里三个TextField与那个勾选框的最终外观全部来自这里。
五、落地与二次开发建议
- 复制范围:把
sign-up/与shared-theme/两个目录整体拷入项目后,按需删除未使用的.js/.tsx冗余版本与AppTheme的disableCustomTheme逻辑(后者仅文档站需要); - 改品牌色:只改 themePrimitives.ts 的
brand色阶即可全局生效,无需逐个组件修改; - 改校验规则:在
validateInputs中调整正则与长度限制即可,模板采用“DOM 取值 + 正则”的轻量方式,若项目已有受控状态或表单库(如 React Hook Form),可将其替换为对应实现; - 对接后端:把
handleSubmit中的console.log替换为真实注册接口,并在此处处理服务端错误提示(模板预留的xxxErrorMessage状态可直接复用); - 社交登录:将
alert('Sign up with Google')等占位onClick替换为 OAuth 流程,并删除CustomIcons.tsx中不再使用的图标。
以上路径均可在仓库中直接查看:模板入口 sign-up/README.md、组件源码 SignUp.tsx、共享主题 shared-theme/AppTheme.tsx,以及可与模板组合成完整起步应用的示例项目 examples/material-ui-nextjs。
【免费下载链接】material-uiMaterial UI: Comprehensive React component library that implements Google's Material Design. Free forever.项目地址: https://gitcode.com/GitHub_Trending/ma/material-ui
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考