news 2026/6/9 21:20:32

【前端】从零开始搭建现代前端框架:React 19、Vite、Tailwind CSS、ShadCN UI-第六章《全局尺寸系统(sm / md / lg)—— 响应式组件尺寸与全局 UI 设置》

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【前端】从零开始搭建现代前端框架:React 19、Vite、Tailwind CSS、ShadCN UI-第六章《全局尺寸系统(sm / md / lg)—— 响应式组件尺寸与全局 UI 设置》

本章将正式实现你的框架需求之一:大 / 中 / 小 三种尺寸体系(Large / Medium / Small),并且做到:

  • 全局控制(Zustand 管理)

  • 组件级覆盖(Button、Input、Card 等自动适配)

  • 与 shadcn/ui 的 variant 体系完美兼容

  • 与主题与语言系统协同工作

  • 支持未来扩展(如文字大小、行距、spacing 等)

  • 保证企业级 UI 一致性

本章的尺寸体系将贯穿整个 UI 组件系统,是专业管理后台不可或缺的能力。


第 6 章:全局尺寸系统(sm / md / lg)—— 统一 UI 尺寸控制体系

现代后台系统通常需要两类尺寸:

  • 全局尺寸(系统级别):例如后台全局切换“大号”字体或“紧凑模式”

  • 组件尺寸(组件级别):例如 Button size="lg" 或 Card size="sm"

本章将实现一个:

  • 全局尺寸(sm / md / lg)

  • 默认组件尺寸为全局尺寸

  • 组件允许单独覆盖尺寸

  • 全局变化时所有组件同步更新

  • 下拉切换控制器 UI(SizeSwitcher)

  • 配合 Tailwind + CVA 实现可扩展的尺寸 token

最终效果:

  • App 顶部有一个尺寸切换器

  • 切换后所有组件自动响应:按钮变大、输入框变大、卡片 padding 变大

  • 单个组件仍可使用size="sm"覆盖全局配置


6.1 使用 Zustand 管理全局尺寸状态

首先创建目录:

src/stores/ui.ts

写入:

import { create } from "zustand"; export type UISize = "sm" | "md" | "lg"; interface UIState { size: UISize; setSize: (size: UISize) => void; } export const useUIStore = create<UIState>((set) => ({ size: "md", // 默认中等 setSize: (size) => set({ size }), }));

状态结构非常简单:

  • size: 当前全局尺寸

  • setSize: 切换尺寸方法

未来如果需要扩展(如 UI 密度、字体大小、圆角大小),可以继续放到这个 store 中。


6.2 创建尺寸切换组件

在:

src/components/SizeSwitcher.tsx

创建:

import { useUIStore } from '../stores/ui'; export const SizeSwitcher = () => { const { size, setSize } = useUIStore(); return ( <select className="rounded-md border px-2 py-1" value={size} onChange={(e) => setSize(e.target.value as 'sm' | 'md' | 'lg')} > <option value="sm">Small</option> <option value="md">Medium</option> <option value="lg">Large</option> </select> ); };

用ShadCn实现

import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { useUIStore } from '../stores/ui'; export const SizeSwitcher = () => { const { size, setSize } = useUIStore(); return ( <Select value={size} onValueChange={(value) => setSize(value as 'sm' | 'md' | 'lg')}> <SelectTrigger className="w-[180px]"> <SelectValue placeholder="Select size" /> </SelectTrigger> <SelectContent> <SelectItem value="sm">Small</SelectItem> <SelectItem value="md">Medium</SelectItem> <SelectItem value="lg">Large</SelectItem> </SelectContent> </Select> ); };

6.3 将 SizeSwitcher 集成到 App 里测试

修改src/App.tsx

import { Search, User, Settings, Plus } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { Button } from '@/components/ui/button'; import { LanguageSwitcher } from './components/LanguageSwitcher'; import { SizeSwitcher } from './components/SizeSwitcher'; import { ThemeSwitcher } from './components/ThemeSwitcher'; function App() { const { t } = useTranslation(); return ( <div className="flex min-h-screen flex-col items-center justify-center gap-4 space-x-3 p-4"> <div>App Initialized</div> <Button>默认按钮</Button> <Button size="sm">小</Button> <Button size="lg">大</Button> <Button variant="outline">描边按钮</Button> <IconDemo /> <CreateButton /> <LanguageSwitcher /> <h1 className="text-2xl font-bold">{t('dashboard.title')}</h1> <p>{t('dashboard.welcome', { name: '龙傲天' })}</p> <div>{t('common.language')}</div> <ThemeSwitcher /> <h1 className="text-2xl font-bold">Theme System Ready</h1> <div className="rounded-md border bg-card p-4 text-card-foreground"> This box will change when you toggle theme. </div> <div className="bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))]"> 主题变量测试 </div> <SizeSwitcher /> <h1 className="text-2xl font-bold">Global UI Size System</h1> <div className="space-x-3"> <Button>Button</Button> <Button variant="outline">Outline</Button> <Button size="lg">Override lg</Button> </div> </div> ); } function IconDemo() { return ( <div className="flex items-center gap-4"> <Search className="h-5 w-5 text-muted-foreground" /> <User className="h-5 w-5 text-blue-500" /> <Settings className="h-5 w-5 text-green-500" /> </div> ); } function CreateButton() { return ( <Button> <Plus className="mr-2 h-4 w-4" /> 新建 </Button> ); } export default App;

此时尺寸切换器已经能改变 Button 尺寸,但我们需要完善组件逻辑。


6.4 让组件自动读取全局尺寸(Button 示例)

你的 shadcn Button 文件如下(根据前几章):

在:

src/components/ui/button.tsx

修改:

import * as React from "react" import { cn } from "@/lib/utils" import { useUIStore } from "@/stores/ui" const componentSizes = { sm: "px-2 py-1 text-sm", md: "px-3 py-2 text-base", lg: "px-4 py-3 text-lg", } export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { size?: "sm" | "md" | "lg" | "auto"; // auto = follow global variant?: "default" | "outline" | "ghost"; } export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( ({ className, size = "auto", variant = "default", ...props }, ref) => { const globalSize = useUIStore((s) => s.size); const finalSize = size === "auto" ? globalSize : size; return ( <button ref={ref} className={cn( "rounded-md font-medium transition-colors", componentSizes[finalSize], variant === "outline" ? "border border-input hover:bg-accent hover:text-accent-foreground" : "bg-primary text-primary-foreground hover:bg-primary/90", className )} {...props} /> ); } ); Button.displayName = "Button";

现在 Button 有三种尺寸应用方式:

用法说明
<Button />使用全局尺寸
<Button size="lg" />覆盖为大号尺寸
<Button size="sm" />覆盖为小号尺寸
<SizeSwitcher />控制全局尺寸

完美符合企业 UI 要求。


6.5 为 Input、Card 等组件添加全局尺寸支持(范例)

强烈推荐在组件目录中建立一个公共尺寸工具:

src/components/ui/useComponentSize.ts

内容:

import { useUIStore } from "@/stores/ui"; export const useComponentSize = (size?: "sm" | "md" | "lg" | "auto") => { const globalSize = useUIStore((s) => s.size); return size === "auto" || !size ? globalSize : size; };

之后每个组件都可以这样写:

const finalSize = useComponentSize(size)

让我们为 Input 组件建立一个尺寸支持:

(生成 input):

pnpm dlx shadcn-ui@latest add input

编辑文件:

src/components/ui/input.tsx

添加:

import { useComponentSize } from "./useComponentSize"; const inputSizes = { sm: "h-7 px-2 text-sm", md: "h-9 px-3 text-base", lg: "h-11 px-4 text-lg", }; export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> { size?: "sm" | "md" | "lg" | "auto"; } const Input = React.forwardRef<HTMLInputElement, InputProps>( ({ className, type, size = "auto", ...props }, ref) => { const finalSize = useComponentSize(size); return ( <input type={type} className={cn( "border rounded-md bg-background focus:ring-2", inputSizes[finalSize], className )} ref={ref} {...props} /> ); } );

输入框也具备全局尺寸能力。


6.6 UI 尺寸系统设计原理(重要理解)

你的尺寸系统遵循两层设计

第一层:系统 UI 尺寸(sm / md / lg)

存储在 Zustand。

全局作用于所有组件的默认尺寸。

第二层:组件本身的尺寸参数(size="sm")

覆盖第一层。

优先级:

组件尺寸 > 全局尺寸

如:

<SizeSwitcher /> // 全局尺寸 = lg <Button /> // 自动变成 lg <Button size="sm" />// 单独变成 sm

非常灵活。


6.7 在顶级 Layout 中使用(后续章节会使用)

最终,你会在:

src/components/Layout.tsx

放置:

<header className="flex items-center justify-between p-4 border-b"> <LanguageSwitcher /> <ThemeSwitcher /> <SizeSwitcher /> </header>

这是企业后台的经典“全局配置栏”。


6.8 本章小结

本章完成了:

✔ 全局尺寸状态(Zustand)
✔ 尺寸切换器(SizeSwitcher)
✔ Button 支持全局尺寸 + 局部覆盖
✔ 创建 useComponentSize 钩子
✔ Input 等组件也支持尺寸系统
✔ App 整体可响应大小变化
✔ 为后续所有 UI 组件奠定一致规范

至此,你的项目现在拥有完整的 UI 三尺寸体系,并可与:

  • theme 主题系统

  • shadcn UI

  • Tailwind

  • i18n

  • 动态路由

  • 权限

协同工作。

项目已经具备成熟后台框架的视觉基础。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 17:16:08

这个Pytest函数,轻松实现动态参数化√

无论什么自动化&#xff0c;部分测试用例均会运用到参数化&#xff0c;参数化可以帮助我们覆盖更多的测试用例&#xff0c;减少重复代码逻辑&#xff0c;然而自动化中也有多种实现参数化的方法&#xff0c;比如UnitTest的DDT模式&#xff0c;Pytest的fixture&#xff0c;以及Py…

作者头像 李华
网站建设 2026/6/8 18:10:33

竞赛毕业设计作品定做---【芳心科技】F. STM32 智驱便携电脉冲针刺仪

实物效果图&#xff1a;实现功能&#xff1a;1. 采用 STM32 单片机作为控制核心。 2. 采用 MOSFET 开关管控制电极片的频率。 3. 通过电开关改变电极片的振幅。 4. 通过三极管改变电极片的电流。 5. 采用 LCD 显示屏进行显示。 6. 按键设置频率、振幅和电流数值。原理图&#x…

作者头像 李华
网站建设 2026/5/27 21:04:29

【Java毕设源码分享】基于springboot+vue的疫情防控自动售货机系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/7 19:25:26

梁文锋的“左右互搏”:宕机的DeepSeek与闷声发财的幻方

深夜23点&#xff0c;北京国贸写字楼的灯光只剩零星几点。程序员小林盯着屏幕上刺眼的“服务器繁忙”提示&#xff0c;第三次尝试调用DeepSeek API失败。就在他为瘫痪的程序焦头烂额时&#xff0c;千里之外的杭州&#xff0c;幻方量化的交易系统正自动完成一笔高频交易&#xf…

作者头像 李华
网站建设 2026/6/9 18:42:45

Visual Basic编程规范指南:Dassault Systèmes产品线脚本开发最佳实践

Visual Basic编程规范在Dassault Systmes产品线脚本开发中扮演着关键角色,尤其在确保脚本可测试性和跨平台兼容性方面。基于CATIA VBA环境的特殊性,本指南旨在提供一套系统化的编码规则,帮助开发者创建高效、可靠且易于维护的脚本。这些规则不仅适用于简单的宏脚本,也适用于…

作者头像 李华