





























面对“多端界面不同,但数据源和业务逻辑一致”的挑战,现代前端架构的核心思想是:最大化共享数据逻辑与业务规则,最小化 UI 表现层的差异成本。它不再靠“多套完全独立的代码”,而是通过分层架构、共享数据 Hooks 和设计令牌,让各端各自独立渲染,但底层逻辑完全统一。
┌──────────────────────────────────────────────────────┐
│ 各端 UI 壳 │
│ 桌面 (Table/复杂表单) 手机 (卡片/底部导航) 大屏 (全屏图表) │
└───────────────┬──────────────────────────────────────┘
│ 调用共享 Hooks / 服务
┌───────────────▼──────────────────────────────────────┐
│ 共享业务逻辑层 (Monorepo packages) │
│ • API 类型定义 • 数据获取 Hooks (React Query) │
│ • 业务校验函数 • 状态管理 (Zustand) • 设计令牌 │
└───────────────┬──────────────────────────────────────┘
│
┌───────────────▼──────────────────────────────────────┐
│ 可选的 BFF (Backend for Frontend) │
│ 桌面 BFF (聚合表格数据) 手机 BFF (精简字段) │
└───────────────┬──────────────────────────────────────┘
│
┌───────────────▼──────────────────────────────────────┐
│ 统一后端微服务 / API │
│ 用户服务 · 订单服务 · 分析服务 · 权限服务 │
└──────────────────────────────────────────────────────┘
关键点:
smart-platform/
├── apps/
│ ├── desktop/ # 桌面端 (React + Ant Design)
│ │ ├── src/
│ │ │ ├── layouts/ # 经典顶栏+侧边双菜单
│ │ │ ├── pages/ # 表格、复杂表单
│ │ │ └── App.tsx
│ ├── mobile/ # 移动端 (React + 自定义移动组件)
│ │ ├── src/
│ │ │ ├── layouts/ # 底部导航 + 抽屉
│ │ │ ├── pages/ # 卡片流、滑动操作
│ │ │ └── App.tsx
│ └── bigscreen/ # 大屏 (React + ECharts)
│ ├── src/
│ │ ├── layouts/ # 全屏网格无菜单
│ │ ├── pages/ # 实时数据看板
│ │ └── App.tsx
└── packages/
├── shared-hooks/ # 数据获取与业务逻辑 Hooks
│ ├── useUsers.ts
│ ├── useOrders.ts
│ └── validators.ts
├── shared-types/ # API 接口类型
├── shared-state/ # 全局状态 atoms (Zustand)
├── design-tokens/ # 跨平台设计令牌
└── ui-kit/ # 可选的基础 UI 原子 (Button, Input)
以“用户管理”为例,三个端界面完全不同:
它们共享的代码只有一份:
// packages/shared-hooks/useUsers.ts
import { useQuery } from '@tanstack/react-query';
import { fetchUsers } from '../services/userApi';
import type { UserFilters } from '../shared-types';
export function useUsers(filters: UserFilters) {
return useQuery({
queryKey: ['users', filters],
queryFn: () => fetchUsers(filters),
staleTime: 30_000, // 各端一致的缓存策略
});
}
// packages/shared-hooks/validators.ts
export const validateEmail = (email: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
export const canDeleteUser = (user, currentUserRole) => { /* 权限逻辑 */ }
桌面端使用:
// apps/desktop/pages/UserList.tsx
import { Table, Button } from 'antd';
import { useUsers } from '@smart-platform/shared-hooks';
export default function UserList() {
const { data, isLoading } = useUsers({ status: 'active' });
return <Table dataSource={data} columns={columns} />;
}
手机端使用:
// apps/mobile/pages/UserList.tsx
import { useUsers } from '@smart-platform/shared-hooks';
import { CardList } from '../components/CardList';
export default function UserList() {
const { data, refetch } = useUsers({ status: 'active' });
return <CardList data={data} onRefresh={refetch} />;
}
结果: 逻辑完全一致,UI 随意定制,代码零重复。
如果移动端需要的字段明显少于桌面端,或大屏需要特殊的聚合数据,可以让 BFF 层做适配,但共享 Hooks 依然调用同一函数,只是传入不同的 API endpoint 或参数:
// packages/shared-hooks/useDashboard.ts
export function useDashboard(device: 'desktop' | 'mobile' | 'bigscreen') {
const endpoint = {
desktop: '/api/desktop/dashboard',
mobile: '/api/mobile/dashboard',
bigscreen: '/api/bigscreen/dashboard',
}[device];
return useQuery({ queryKey: ['dashboard', device], queryFn: () => fetch(endpoint) });
}
每个 BFF 接口由后端统一维护,业务规则依然在服务层集中,只是组装数据时按需裁剪,避免移动端加载不必要的字段。
即使界面不同,视觉语言和间距体系应该统一,这依赖我们之前定义的设计令牌。各端应用都引用同一份 CSS 变量,但允许在局部覆盖参数:
/* packages/design-tokens/global.css */
:root {
--color-primary: #4f46e5;
--grid-min-col: 300px;
--grid-gap: 24px;
}
手机端可以在入口处覆盖:
/* apps/mobile/src/styles.css */
body {
--grid-min-col: 160px;
--grid-gap: 12px;
}
桌面端的复杂表格依然可以享受弹性栅格带来的列数自适应,大屏的 --grid-min-col 可能设为 500px,各端按需取值,但共享令牌名称。
当界面差异极大且变化频繁时,可引入元数据驱动 UI。将“用户列表”抽象为一份描述文件:
# user-module-meta.yaml
entity: User
features: [list, create, delete]
list:
desktop: TableView
mobile: CardView
bigscreen: LiveTicker
api: /api/users
各端引擎根据这份元数据加载不同的预设组件,共享的 useUsers Hook 自动绑定。这样,新增一个模块只需写一份元数据和后端接口,三端自动获得对应视图(可覆盖)。
这套方案完美平衡了精细控制与维护成本,是从“古典 Web 多套代码”到“AI 原生超级系统”演进中,现阶段最务实的工程选择。你的团队可以立即从 Monorepo + shared-hooks 开始,逐步叠加 BFF 和元数据驱动,既满足当前多端差异需求,又为未来留下扩展空间。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。