前言

  • 后台管理系统用的非常多,如果比较复杂点的后台可能会多人开发,这时候可能导致各种样式不统一之类的问题。
  • antdpro用起来有一定学习成本,所以需要梳理一下。

快速上手

npx create-umi your-project
  • 选择最新v5,antd4

  • 启动

npm run start
  • 即可看见页面。
  • 登录页默认用户名密码是admin ant.design 。输入进去即可进入后台。
  • 进入后右下角有个米饭一样的图标,那个就是umi-ui,可以非常方便的导入代码或者模板进行修改。
  • 注意!尽量别用umi-ui导入模板,容易引起各种问题。而且是一个不可逆的过程!同时,很多模板没有人维护,使用的是老的api或者写法,也容易导致各种bug!
  • 读者可以玩一下,这玩意就是我最初学前端非常想要的功能。不仅仅是复制代码,包括路由什么的都整好了。

概念

  • 使用antdpro,首先默认你已经会了react dva ts umi antd(里面很多组件和antd关系比较大,没熟练用过antd的要花更多时间上手)

配置

  • config文件夹下3个文件,相当于原umirc的配置:
  • 路由参考:https://beta-pro.ant.design/docs/layout-cn
  • defaultSettings主要用来配置主题
  • proxy主要就是devserver的代理。
  • antdpro整了react环境变量,你可以看见在proxy里分别配了3个环境,当然都是开发环境,对应着3个start脚本。

主题

  • 优先使用官方提供的工具先看一下哪种主题好:https://preview.pro.ant.design/dashboard/analysis/
  • 然后复制粘贴到defaultSettings中。
  • 当然你也可以在自己的站点里使用它,需要将PageContainer, SettingDrawer, ProSettings从pro-layout里导出后自己实现。
  • 具体参考:https://pro.ant.design/blog/new-pro-use-cn#settingdrawer

布局

  • 一般小项目不会用这玩意的,如果用了antdpro可能对样式什么的有需求,所以antdpro还整了个可视化配置样式插件。
  • 这个也是为啥在antd的基础上封了个proxxx组件,而且这些组件把常用的逻辑都写差不多了,只要修改对应的地方就行了,没人用的主要原因就是又大又重,他们称之为重型组件,有些地方想定制比较难下手,还是需要把所有代码以及配置都搞懂。
  • 参考官网:https://procomponents.ant.design/components/

请求

  • 里面的很多loading都是使用umihook的useRequest:
import React from 'react';
import { useRequest } from 'umi';
import services from '@/services/afs2demo';

const YourComponent: React.FC = () => {
  const { data, loading } = useRequest(() => {
    return services.AccountController.addAccount();
  });
  if (loading) {
    return <>Loading...</>;
  }
  return <div>{data?.name}</div>;
};

export default YourComponent;
  • 这样避免写太多loading,同时可以配合table使用。useRequest的参数的函数的返回值是一个promise,一般是每个页面的serverice.ts下定义的请求:
import { request } from 'umi';
import { TableListParams, TableListItem } from './data.d';

export async function queryRule(params?: TableListParams) {
  return request('/api/rule', {
    params,
  });
}
  • umi-request在app.tsx下有个errorHandler已经写好了个异常处理。
  • 中间件处理需要加上配置:
export const request = {
  middlewares: [
    async function middlewareA(ctx, next) {
      console.log('A before');
      await next();
      console.log('A after');
    },
    async function middlewareB(ctx, next) {
      console.log('B before');
      await next();
      console.log('B after');
    }
  ]
}
  • 拦截器处理也是一样:
requestInterceptors?: RequestInterceptor[];
  responseInterceptors?: ResponseInterceptor[];

MOCK

  • 约定mock文件夹下的为mock数据,具体可以参考:https://umijs.org/zh-CN/docs/mock
  • 如果你不想用mock,可以配置关闭:
export default {
  mock: false,
};
  • 或者使用命令不开:
MOCK=none umi dev

数据流

  • antdpro5中使用了新的数据流可以代替dva,这样在纯hooks组件下更加轻量好理解,也容易方便管理并且没有学习成本。
  • 这个是通过plugin-model实现的功能,约定model下的文件为一个id,然后就像使用自定义hook一样使用它,但是这个状态是全局的,另外状态更新各个组件都可以更新 。
  • dva学习成本还是略高的,就算你学会了,别人不一定能很快学会,而这个就不一样了。
  • 初始数据:
export async function getInitialState() {
  return {
    userName: 'xxx',
  };
}
  • app中有个getInitialState方法用来做全局的初始数据,依靠 @umijs/plugin-initial-state插件完成。
  • 同样,这个也是个model,只是它自带的:
import React from 'react';

import { useModel } from 'umi';
import { Spin } from 'antd';

export default () => {
  const { initialState, loading, refresh, setInitialState } = useModel('@@initialState');

  if (loading) {
    return <Spin />;
  }

  return <div>{initialState.userName}</div>;
};
DVA
  • 5版本的model同样也支持dva,这是因为plugin-dva的获取文件后对导出进行了校验。
/* eslint-disable no-param-reassign */
import { Effect, ImmerReducer, Subscription } from 'umi';

export interface IndexModelState {
  name: string;
}
export interface IndexModelType {
  namespace: 'index';
  state: IndexModelState;
  effects: {
    query: Effect;
  };
  reducers: {
    save: ImmerReducer<IndexModelState>;
  };
  subscriptions: { setup: Subscription };
}
const IndexModel: IndexModelType = {
  namespace: 'index',
  state: {
    name: '',
  },
  effects: {
    *query({ payload }, { put }) {
      yield put({
        type: 'save',
        payload,
      });
    },
  },
  reducers: {
    save(state, action) {
      state.name = action.payload;
    },
  },
  subscriptions: {
    setup({ dispatch, history }) {
      return history.listen(({ pathname }) => {
        if (pathname === '/testdemo') {
          dispatch({
            type: 'query',
            payload: 'yehuozhili',
          });
        }
      });
    },
  },
};
export default IndexModel;
  • 页面中使用需要connect后props获取:
import React, { FC } from 'react';
import { IndexModelState, ConnectProps, Loading, connect } from 'umi';

interface PageProps extends ConnectProps {
  index: IndexModelState;
  loading: boolean;
}
const IndexPage: FC<PageProps> = ({ index, dispatch, loading }) => {
  const { name } = index;
  return <div>Hello {name}</div>;
};
export default connect(({ index, loading }: { index: IndexModelState; loading: Loading }) => ({
  index,
  loading: loading.models.index,
}))(IndexPage);

权限

  • 权限参考资料:https://beta-pro.ant.design/docs/authority-management-cn
  • 权限实质就是个高阶组件,思想有点类似于守卫的意思,src下有个access的文件,里面设置了权限以及判定。具体可以根据业务需要来,主要就是业务返回某个权限值,然后基于权限值判断:
// src/access.ts
export default function access(initialState: { currentUser?: API.CurrentUser | undefined }) {
  const { currentUser } = initialState || {};
  return {
    canAdmin: currentUser && currentUser.access === 'admin',
    canGuset: currentUser && currentUser.access === 'guest',
  };
}
  • 比如我加一个canGuest表明某个页面只能由guest进行访问。
  • 在mock文件夹里模拟着返回值,其中有句:
'POST /api/login/account': (req: Request, res: Response) => {
    const { password, username, type } = req.body;
    if (password === 'ant.design' && username === 'admin') {
      res.send({
        status: 'ok',
        type,
        currentAuthority: 'admin',
      });
      access = 'admin';
      return;
    }
    if (password === 'ant.design' && username === 'user') {
      res.send({
        status: 'ok',
        type,
        currentAuthority: 'user',
      });
      access = 'user';
      return;
    }
    if (type === 'mobile') {
      res.send({
        status: 'ok',
        type,
        currentAuthority: 'admin',
      });
      return;
    }
  • 也就是以admin登录,是admin权限。
  • 可以试着在路由配置中对权限进行控制:
{
      name: 'test',
      icon: 'smile',
      path: '/testdemo',
      access: 'canGuset',
      component: './testdemo',
    },
  • 此时,以admin身份登录/testdemo则会出现401页面。
  • 将mock文件的那句改为guest再次访问,即可出现想要的页面。
  • 组件中使用:
 const access = useAccess();
  • 即可拿到access.ts所定义的权限。

国际化

  • 国际化参考文档:
  • https://beta-pro.ant.design/docs/i18n-cn
  • https://umijs.org/zh-CN/plugins/plugin-locale#%E4%BB%8B%E7%BB%8D
  • 约定 在 src/locales 中引入 相应的 js,例如 en-US.ts 和 zh-CN.ts,并且在 config/config.ts 中做如下配置:
plugins:[
  ...,
  locale: {
    enable: true,
    default: 'zh-CN',
    baseNavigator: true,
  },
  ...,
]
  • 它使用的是react-intl :https://formatjs.io/docs/getting-started/installation/
  • 这个库有很多高级功能,比如动态导入什么的,所以还是比较大的。
  • layout中若设置了国际化,默认配置的route的name就是国际化的key值。
  • 如果你写了对应的zh-CN.ts,默认会

重型组件PRO

  • 了解了上面的设定,基本可以玩了,下面还需要了解antdpro特有的重型组件,来使得样式保持统一。

ProLayout - 高级布局

  • prolayout是高级布局,是一开始就自带的。
  • 可以通过context拿到布局上下文:
import { RouteContext, RouteContextType } from '@ant-design/pro-layout';
const Page = () => (
  <RouteContext.Consumer>
    {(value: RouteContextType) => {
      return value.title;
    }}
  </RouteContext.Consumer>
);
  • routerContext里面还有个很常用的就是isMobile,如果需要对手机端支持,拿此参数判断。
  • plugin-layout将layout的代码写入.umi,所以用户可以完全不用管路由,我个人觉得这玩意相当好。其实确实这东西不需要怎么自定义。如果想自定义的可以关掉layout,手动引入ProLayout或者自己写layout。
  • https://procomponents.ant.design/components/layout#api
  • PageContainer是一个壳,它可以显示嵌入页面的底色,也可以显示白色,另外提供面包屑功能,这个面包屑,1级菜单是不显示的,如果想显示,需要修改app.tsx。

ProTable - 高级表格

  • https://procomponents.ant.design/components/table
  • 这玩意配置项太多,因为不只是表格,会带着别的东西,所以还需要耐下心来先挑选满足自己要求的表格,然后自定义的地方再仔细看配置。

ProForm - 高级表单

  • https://procomponents.ant.design/components/form
  • 这个主要是登录注册,或者是让用户填表单的地方,同样是一个组件一个页面。

ProCard - 高级卡片

  • https://procomponents.ant.design/components/card
  • 如果你想让padding固定,有个比较美观的样式,那就需要使用它。
  • 卡片不仅仅是那种小的,它可以去承载别的之类。在一开始布局时可以调整好。

ProDescriptions - 高级定义列表

  • 这玩意是按固定格式的白板,类似于antd的descriptions
  • https://procomponents.ant.design/components/descriptions

ProList - 高级列表

  • 这组件是自带padding的,需要列表时可以使用。
  • https://procomponents.ant.design/components/list
Logo

快速构建 Web 应用程序

更多推荐