015 在 Umi 中使用 Ant Design 编写全局布局

简介: 015 在 Umi 中使用 Ant Design 编写全局布局

image.png


前面14天的内容,我们几乎都在谈论 Umi 的相关概念,从这节课开始,我们就会真正进入实战阶段,如果需要给它取一个小标题,那我大概率会用《如何手写 Ant Design Pro》


这节课我们来实现页面级整体布局,所谓布局简单的理解就是网页的整体框框,也可以看成是,所有页面都共用的部分。 比如在 pc 上比较常见的上中下布局,在 app 上的底部 tabs 、全局浮动球等都属于布局需求。



约定的全局布局

约定式路由时的全局布局文件,实际上是在路由外面套了一层。比如,你的路由是:

约定 src/layouts/index.tsx 为全局路由,实际上是在路由外面套了一层返回一个 React 组件,并通过 useOutlet hook 或者 Outlet 组件渲染子组件。

比如以下目录结构,


.
└── src
    ├── layouts
    │   └── index.tsx
    └── pages
        ├── index.tsx
        └── users.tsx
复制代码


会生成路由,

[
  { exact: false, path: '/', component: '@/layouts/index',
    routes: [
      { exact: true, path: '/', component: '@/pages/index' },
      { exact: true, path: '/users', component: '@/pages/users' },
    ],
  },
]
复制代码


从组件角度可以简单的理解为如下关系:

<layout>
  <page>index</page>
  <page>users</page>
</layout>
复制代码


一个自定义的全局 layout 如下:

import React from "react";
import { useOutlet } from "umi";
const Layout = () => {
  const outlet = useOutlet();
  return (
    <div>
      Layout
      {outlet}
    </div>
  );
};
export default Layout;
复制代码



不同的全局 layout

你可能需要针对不同路由输出不同的全局 layout,Umi 不支持这样的配置,但你仍可以在 src/layouts/index.tsx 中对 location.path 做区分,渲染不同的 layout 。

比如想要针对 /login 输出简单布局,


import React from "react";
import { useOutlet } from "umi";
export default function(props) {
  const outlet = useOutlet();
  if (props.location.pathname === '/login') {
    return <SimpleLayout>{ outlet }</SimpleLayout>
  }
  return (
    <>
      <Header />
      { outlet }
      <Footer />
    </>
  );
}
复制代码



使用 Ant Design 实现基本布局

Ant Design 提供了好几种的布局方式,几乎中后台的所有布局都包括了。

image.png

详细的范例可以参考 Ant Design 官网,这里我们用最常见的 顶部导航 Header、侧边栏 Sider、内容区 Content、底部区域 Footer 的布局来做演示。


安装 Ant Design 和图标库

pnpm i antd @ant-design/icons
复制代码


使用 umi antd 插件

config/config.ts 配置中,修改 plugins 配置

import { defineConfig } from "umi";
export default defineConfig({
  // 最终值在插件中设置,所以这里不用写
  //   title: "Hello Umi",
  plugins: [
    require.resolve("@umijs/plugins/dist/model"),
+   require.resolve("@umijs/plugins/dist/antd"),
  ],
  model: {},
  antd: {},
});
复制代码


开启 antd 插件功能

config/config.ts 配置中,新增 antd 配置,这里是一次强调,添加完插件,要记得添加对应的配置。

Umi 中部分插件是默认开启,就无须配置。正常的插件都是配置开关。所有的插件都可以通过配置值为 false,来关闭它。

import { defineConfig } from "umi";
export default defineConfig({
  // 最终值在插件中设置,所以这里不用写
  //   title: "Hello Umi",
  plugins: [
    require.resolve("@umijs/plugins/dist/model"),
    require.resolve("@umijs/plugins/dist/antd"),
  ],
  model: {},
+ antd: {},
});
复制代码


新建 Layout 页面

新建页面文件 src/layouts/index.tsx,写出整体布局(用法来自 Ant Design 官网)

import { Layout } from "antd";
import React from "react";
const { Header, Content, Footer, Sider } = Layout;
const App: React.FC = () => {
  return (
    <Layout style={{ minHeight: "100vh" }}>
      <Sider></Sider>
      <Layout>
        <Header style={{ padding: 0 }} />
        <Content style={{ margin: "0 16px" }}></Content>
        <Footer style={{ textAlign: "center" }}></Footer>
      </Layout>
    </Layout>
  );
};
export default App;
复制代码


编写 Sider 和 Menu

import {
  DesktopOutlined,
  FileOutlined,
  PieChartOutlined,
  TeamOutlined,
  UserOutlined,
} from "@ant-design/icons";
import type { MenuProps } from "antd";
import { Breadcrumb, Layout, Menu } from "antd";
import React, { useState } from "react";
const { Header, Content, Footer, Sider } = Layout;
type MenuItem = Required<MenuProps>["items"][number];
function getItem(
  label: React.ReactNode,
  key: React.Key,
  icon?: React.ReactNode,
  children?: MenuItem[]
): MenuItem {
  return {
    key,
    icon,
    children,
    label,
  } as MenuItem;
}
const items: MenuItem[] = [
  getItem("Option 1", "1", <PieChartOutlined />),
  getItem("Option 2", "2", <DesktopOutlined />),
  getItem("User", "sub1", <UserOutlined />, [
    getItem("Tom", "3"),
    getItem("Bill", "4"),
    getItem("Alex", "5"),
  ]),
  getItem("Team", "sub2", <TeamOutlined />, [
    getItem("Team 1", "6"),
    getItem("Team 2", "8"),
  ]),
  getItem("Files", "9", <FileOutlined />),
];
const App: React.FC = () => {
  const [collapsed, setCollapsed] = useState(false);
  return (
    <Layout style={{ minHeight: "100vh" }}>
      <Sider
        collapsible
        collapsed={collapsed}
        onCollapse={(value) => setCollapsed(value)}
      >
        <div
          style={{
            height: "32px",
            margin: "16px",
            color: "#fff",
            textAlign: "center",
            fontSize: "16px",
          }}
        >
          Umi 4
        </div>
        <Menu
          theme="dark"
          defaultSelectedKeys={["1"]}
          mode="inline"
          items={items}
        />
      </Sider>
      {/* Layout 略 */}
    </Layout>
  );
};
export default App;
复制代码


编写 Footer

<Footer style={{ textAlign: "center" }}>
    Umi@4 实战小册 Created by xiaohuoni
</Footer>
复制代码


编写 Content 和面包屑

<Content style={{ margin: "0 16px" }}>
    <Breadcrumb style={{ margin: "16px 0" }}>
        <Breadcrumb.Item>User</Breadcrumb.Item>
        <Breadcrumb.Item>Bill</Breadcrumb.Item>
    </Breadcrumb>
    <div style={{ padding: 24, minHeight: 360 }}>Bill is a cat.</div>
</Content>
复制代码


渲染当前页面

前面提到过,我们使用 useOutlet hook 或者 Outlet 组件渲染子组件。将上面 Content 中的 Bill is a cat. 替换成 outlet 即可。

import { Outlet } from "umi";
// 其他内容略
<div style={{ padding: 24, minHeight: 360 }}>
    <Outlet />
</div>
复制代码


运行效果

执行 pnpm start 或者 npx umi dev,启动 umi 的开发服务,通过浏览器访问 http://127.0.0.1:8888/

image.png


源码归档

目录
相关文章
|
人工智能 开发框架 物联网
为什么 C# 可能是最好的第一编程语言
C# 是一个全面领域的全能型语言,结合新时代的 .NET 平台,与时俱进的发展创新,未来无限可期!对于带着有色眼镜看待的人们,是否该刮目相看了呢?下面看看行业大佬关于 .NET 的解说。
1562 2
为什么 C# 可能是最好的第一编程语言
|
监控 测试技术
如何进行系统压力测试?
【10月更文挑战第11天】如何进行系统压力测试?
1024 34
|
Web App开发 存储 前端开发
Chrome浏览器的跨域问题
Chrome浏览器的跨域问题
1075 128
Next.js 实战 (二):搭建 Layouts 基础排版布局
本文介绍了作者在Next.js v15.x版本发布后,对一个旧项目的重构过程。文章详细说明了项目开发规范配置、UI组件库选择(最终选择了Ant-Design)、以及使用Ant Design的Layout组件实现中后台布局的方法。文末展示了布局的初步效果,并提供了GitHub仓库链接供读者参考学习。
490 1
Next.js 实战 (二):搭建 Layouts 基础排版布局
|
机器学习/深度学习 搜索推荐 计算机视觉
【阿里云OpenVI-人脸感知理解系列之人脸识别】基于Transformer的人脸识别新框架TransFace ICCV-2023论文深入解读
本文介绍 阿里云开放视觉智能团队 被计算机视觉顶级国际会议ICCV 2023接收的论文 &quot;TransFace: Calibrating Transformer Training for Face Recognition from a Data-Centric Perspective&quot;。TransFace旨在探索ViT在人脸识别任务上表现不佳的原因,并从data-centric的角度去提升ViT在人脸识别任务上的性能。
3488 342
|
存储 SQL 数据管理
阿里云数据库 SelectDB 内核 Apache Doris 如何基于自增列满足高效字典编码等典型场景需求|Deep Dive 系列
自增列的实现,使得 Apache Doris 可以在处理大规模时展示出更高的稳定性和可靠性。通过自增列,用户能够高效进行字典编码,显著提升了字符串精确去重以及查询的性能。使用自增列作为主键来存储明细数据,可以完美的解决明细数据更新的问题。同时,基于自增列,用户可以实现高效的分页机制,轻松应对深分页场景,有效过滤掉大量非必需数据,从而减轻数据库的负载压力,为用户带来了更加流畅和高效的数据处理体验。
857 0
|
前端开发 JavaScript 安全
使用React、TypeScript和Ant Design构建现代化前端应用
使用React、TypeScript和Ant Design构建现代化前端应用
818 0
|
缓存 移动开发
网友需求 - 使用 50 行代码在 Ant Design Pro 中完成 Umi 状态保持的多tabs布局
网友需求 - 使用 50 行代码在 Ant Design Pro 中完成 Umi 状态保持的多tabs布局
2518 1
网友需求 - 使用 50 行代码在 Ant Design Pro 中完成 Umi 状态保持的多tabs布局
|
机器学习/深度学习 编解码 算法
【阿里云OpenVI-视觉生产系列之图片上色】照片真实感上色算法DDColor ICCV2023论文深入解读
图像上色是老照片修复的一个关键步骤,本文介绍发表在 ICCV 2023 上的最新上色论文 DDColor
4274 11
【阿里云OpenVI-视觉生产系列之图片上色】照片真实感上色算法DDColor ICCV2023论文深入解读
|
物联网 开发者 异构计算
facechain人物写真生成工业级开源
facechain人物写真应用自8月11日开源了第一版证件照生成后。目前在github(GitHub - modelscope/facechain: FaceChain is a deep-learning toolchain for generating your Digital-Twin.)上已有5.7K的star,论文链接:FaceChain: A Playground for Identity-Preserving Portrait Generation:https://arxiv.org/abs/2308.14256。
1324 5