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.jsnewpage.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 ChartsX6,这个用到时候再研究。

posted @ 2025-04-29 17:34  破落户儿  阅读(163)  评论(0)    收藏  举报