Ant Design Pro快速入门——页面搭建
纯前端菜鸡,只有一些HTML、CSS和JavaScript的基础,最近配合的前端跑路了,想用Ant Design Pro来快速搭建一套中后台来管理数据,只能自己上了,主要自己也想试试水,从后端的视角看前端,整体偏向于实战。
页面、图标和布局
从本节开始,我打算跟着教程一步步实现一个自动化的工作流管理系统。
基础使用
logo和标题
在项目运行后,我们会在管理页的左上角看见一个logo和标题,那肯定要用自己的,把自己的logo复制到public目录下,然后修改src/defaultSettings.js中的title和logo配置:
const Settings: ProLayoutProps & {
pwa?: boolean;
logo?: string;
} = {
navTheme: 'light',
colorPrimary: '#1890ff',
layout: 'side',
contentWidth: 'Fluid',
fixedHeader: false,
fixSiderbar: false,
footerRender:false,
colorWeak: false,
title: '工作流管理',
pwa: true,
logo: '/mylogo.png',
iconfontUrl: '',
token: {
// 参见ts声明,demo 见文档,通过token 修改样式
//https://procomponents.ant.design/components/layout#%E9%80%9A%E8%BF%87-token-%E4%BF%AE%E6%94%B9%E6%A0%B7%E5%BC%8F
},
};
export default Settings;
具体配置可以根据需要查看ProLayout - 高级布局,我比较感兴趣的是这个语法,这是Typescript的语法,表示交叉类型,它的作用是将个多类型合并为一个类型,新类型会合并包含所有被合并类型的属性,所以Settings的类型相当于ProLayoutProps同时叠加pwa和logo两个属性的新类型,但值得注意的是如果两个类型中有同名属性,且类型冲突的话,会导致错误。
新建页面
新建页面的教程在这里:Ant Design Pro - 新建页面,我比较好奇的是,教程里是使用newpage.js和newpage.less,但示例中用到的却都是***.tsx,这个是文档落后的原因,Ant Design Pro 早期(v4/v5)默认使用 JavaScript(.js),后来全面转向 TypeScript(.tsx)。
| 特性 | TypeScript(.tsx) |
JavaScript(.js) |
|---|---|---|
| 类型检查 | ✅ 更安全,减少运行时错误 | ❌ 无类型检查 |
| 代码提示 | ✅ 智能补全、接口提示 | ❌ 较弱 |
| 维护性 | ✅ 适合中大型项目 | ❌ 适合简单场景 |
| Ant Design Pro 默认 | ✅ v5+ 推荐 | ❌ 旧版方式 |
| 样式方案 | CSS Modules(.module.less) |
普通 .less |
| ---------- | ------------------------------- | ------------- |
| 作用域隔离 | ✅ 自动加哈希,避免冲突 | ❌ 全局样式 |
| 按需加载 | ✅ 配合 Tree Shaking | ❌ 可能冗余 |
| 现代项目推荐 | ✅ Next.js/Umi 默认 | ❌ 逐渐淘汰 |
新建一个/src/page/OK.tsx,告诉我站点启动成功了:
import React from 'react';
const OKPage: React.FC = () => (
<div>站点启动成功</div>
);
export default OKPage;
这个时候想通过http://127.0.0.1:8000/ok是不可能访问到页面的,我们需要在/config/routes.ts中配置一下路由:
export default [
{ path: '/ok', layout: false, component: './OK' },
];
layout: false 表示这个页面不需要布局(没有左侧菜单),如果只是单纯的不想在菜单里展示,可以用hideInMenu:true。
注意:这里我遇见了一个问题,就是
Module not found: Error: [CaseSensitivePathsPlugin]异常,这是因为我的文件名是OK.tsx,而路由配置的是/ok,Webpack中使用了严格的大小写路径检查,以避免跨平台的兼容性问题。
我觉得字体颜色太单调了,于是我又新建了一个OK.module.less文件:
.okContainer{
color: green;
}
然后在OK.tsx中引入:
import React from 'react';
import styles from './OK.module.less'
const OKPage: React.FC = () => (
<div className={styles.okContainer}>站点启动成功</div>
);
export default OKPage;
我发现如果通过div{color: green;}然后再通过div className={styles.div}的这种方法来引入,会污染全局样式,所以最好使用类名选择器,如果确实需要用到全局样式,也可以通过嵌套限制作用域:
/* OK.module.less */
.okPage { /* 外层容器类名 */
div { /* 嵌套写法,仅对 .root 下的 div 生效 */
color: green;
}
}
再通过div className={styles.root}引入来达到只对当前页面生效的效果,继续探究代码,这个React.FC表示一个函数组件,返回一个 React 元素,这里之说以没有return是因为箭头函数的隐式返回特性,等价于:
//OK.tsx
import React from 'react';
import styles from './OK.module.less'
const OKPage: React.FC = () => {
return <div className={styles.okContainer}>站点启动成功</div>
};
export default OKPage;
这个时候我想试试传参,可以通过props来传递参数:
import React from 'react';
import styles from './OK.module.less'
const OKPage: React.FC = (props) => {
return <div className={styles.okContainer}>{props.name},站点启动成功</div>
};
export default OKPage;
在Weclome.tsx中添加一行;
<OKPage name="React"/>
就可以把name参数的值传递给OKPage了,虽然代码运行并不会报错,但代码检测会给出报警提示,更为规范的写法是这样:
import React from 'react';
import styles from './OK.module.less'
interface WelcomeInfo{
name:string
}
const OKPage: React.FC<WelcomeInfo> = ({name}) => {
return <div className={styles.okContainer}>{name},站点启动成功</div>
};
export default OKPage;
记得在React的讲解中我们说过,props 是只读的,不能修改,如果我们期望在组件内部修改值,我们可以使用 React.useState 来实现,这个时候用组件函数就不行了,必须使用类组件:
import React from 'react';
import styles from './OK.module.less'
interface OKState{
count: number;
}
interface OKProps{}
//继承Component并指定 props 和 state 类型
class OKPage extends React.Component<OKProps,OKState>{
constructor(props:OKProps){
super(props);
this.state = {
count: 0
};
}
increment(){
this.setState({
count: this.state.count + 1
});
}
componentDidMount(){
this.setState({
count: 1
});
}
render(){
return <div className={styles.okContainer}>
<p>{this.state.count}</p>
<button onClick={()=>this.increment()}>Incrment</button>
</div>;
}
}
export default OKPage;
注意我这段代码实际上是有问题的:
increment() {
this.setState({
count: this.state.count + 1,
});
}
直接使用了this.state.count + 1,但setState是异步的,所以多次点击时,this.state的状态可能未更新,所以正确的写法应该是:
increment() {
this.setState((prevState) => ({
count: prevState.count + 1,
}));
}
这里的prevState表示前一次的状态,所以prevState.count表示前一次的count的值,这样即使多次点击按钮,this.state.count的值也是正确的。
布局
其官方文档中关于布局的部分和最近的版本有些出入,最新的版本已经将布局的配置转移到了defaultSettings.ts中。
国际化
国际化基本用不到,留着还碍事,直接移除掉好了npm run i18n-remove。
权限
文档中提到了权限问题,这里简要阐述下,后面也要细细研究,找到access.ts文件,添加accessOk: currentUser && currentUser.name === 'ok':
/**
* @see https://umijs.org/docs/max/access#access
* */
export default function access(initialState: { currentUser?: API.CurrentUser } | undefined) {
const { currentUser } = initialState ?? {};
return {
canAdmin: currentUser && currentUser.access === 'admin',
accessOk: currentUser && currentUser.name === 'guest',
};
}
这里定义了accessOk权限,条件是登录的ok账户才能访问,在routes.ts的OK页面配置中添加access:
{ path: '/ok', component: './OK',access:'accessOk' }
这个时候我们再访问OK页面就是403了,如果此时我们将条件从guest改为admin,我们又可以正常访问了。
图表
React支持的图表类型众多,需要额外安装,我看了下我需要用到的有 Ant Design Charts 和 X6,这个用到时候再研究。

浙公网安备 33010602011771号