• Ant Design Pro V5 从服务器请求菜单(typescript版)


    【前言】

    找了很多Admin模板,最后还是看中了AntDesignPro(下文简写antd pro)这个阿里巴巴开源的Admin框架,长这样(还行吧,目前挺主流的):

    官网地址:https://pro.ant.design/index-cn

    该套模板是使用了React开发框架作为基础,AntDesign(蚂蚁金服开源UI组件库)作为UI库,集成了Dva,Umi,Mock等库,如果不是很了解这些内容,门槛还是比较高的。

    我们今天需要实现一个需求:将Antd Pro模板中固定写死的菜单换成从服务器请求菜单然后进行渲染

    为啥非要自己写,官网文档不香吗?----官方文档写的实在太草了,而且目前没有typescript方式的文档,需要踩多少坑...不过没关系,看完这篇坑就都基本填平了

    关于Antd Pro第一步,如何创建并运行Antd Pro,可以移步 https://www.cnblogs.com/7tiny/p/13444963.html

    【了解项目中的dva和Umi用法】

    antd pro 默认采用了Umi和dva组件,因此想要在基础上添加功能必须了解数据请求和数据流向

    在dva中主要分3层,models,services,components,其中models是最重要概念,这里放的是各种数据,与数据交互的应该都是在这里。services是请求后台接口的方法。components是我们编写的组件。

    service层

    service 层仅仅是封装了用request请求服务端的api的逻辑,这里不涉及业务逻辑,比较简单,例如下面代码:

    import request from '@/utils/request';
    
    export interface LoginParamsType {
      userName: string;
      password: string;
      mobile: string;
      captcha: string;
    }
    
    export function fakeAccountLogin(params: LoginParamsType) {
      return request('/api/login/account', {
        method: 'POST',
        data: params,
      });
    }
    
    export async function getFakeCaptcha(mobile: string) {
      return request(`/api/login/captcha?mobile=${mobile}`);
    }
    

    models层

    models层是核心业务逻辑的所在

    import { Effect, Reducer } from 'umi';
    
    import { queryCurrent, query as queryUsers } from '@/services/user';
    
    export interface CurrentUser {
        avatar?: string;
        name?: string;
        title?: string;
        group?: string;
        signature?: string;
        tags?: {
            key: string;
            label: string;
        }[];
        userid?: string;
        unreadCount?: number;
    }
    
    export interface UserModelState {
        currentUser?: CurrentUser;
    }
    
    //定义接口
    export interface UserModelType {
        namespace: 'user';
        state: UserModelState;
        effects: {
            fetch: Effect;
        };
        reducers: {
            saveCurrentUser: Reducer<UserModelState>;
        };
    }
    
    const UserModel: UserModelType = {
        //命名空间,component层调用路由方法的时候需要根据命名空间匹配
        namespace: 'user',
    
        //存放值的地方
        state: {
            currentUser: {},
        },
    
        // 与后台交互,处理数据逻辑的地方
        effects: {
            //业务方法,这里的_是不需要参数,如果需要参数,这里改成传递进来的参数对象即可
            //这里支持call,put,select等几种方法,用call调用service层的方法
            //const m = yield select((state) => state.test.num) //select就是用来选择上面state里的,这里没用上
            *fetch(_, { call, put }) {
                //queryUsers是引入service层那个function的一个名字
                const response = yield call(queryUsers);
                yield put({
                    // 这就是reducer中save方法, put就是用来触发reducer的方法,payload里就是传过去的参数。 同时它也能触发同等级effects中其他方法。
                    type: 'saveCurrentUser',
                    payload: response,
                });
            },
        },
    
        // 能改变界面的action应该放这里,这里按官方意思不应该做数据处理,只是用来return state 从而改变界面
        reducers: {
            //可以理解为一个方法
            saveCurrentUser(state, action) {
                //return新的state,这样页面就会更新 es6语法,就是把state全部展开,然后把currentUser重新赋值
                return {
                    ...state,
                    currentUser: action.payload || {},
                };
            },
        },
    };
    
    export default UserModel;
    

    component组件中调用model层

    在某一个方法里用dispatch即可调用

    clickHandler = () => {
        dispatch({
            type: "user/fetch",// 这里就会触发models层里面effects中fetch方法(也可以直接触发reducer中方法,看具体情况) ,user是命名空间名字
            payload: {
               
            },
        })
    }
    

    这里注意一下type请求的方法路由即可,前面是命名空间,后面是方法名

    使用connect获取dispatch调用后改变的state中的数据

    首先需要在组件接口中定义字段,类型为model中定义的类型,因为要获取model中字段这个值,肯定是同一种类型的

    然后在组件的实现中定义变量,从props中获取值

    在组件代码下方的connect方法中将变量赋值,只有这里赋值了,组件中的常量才可以从props中获取到state中的值

    这里connect方法的参数其实就是各个model中的state,dispatch后,这里便可以获取到修改后的值

    tips:因为使用的是typescript,所以这里的参数需要在ConnectState中先定义:

    【开始改造Antd Pro,实现从服务器请求菜单】

    定义service

    在src/services文件夹下新增文件 menu.ts

    import request from '@/utils/request';
    
    export async function query(): Promise<any> {
      return request('/api/getmenu');      //这里是服务端的获取菜单的地址,根据自己情况进行调整
    }
    

    定义model

    在src/models文件夹下新增文件 menu.ts

    import { Effect, Reducer } from 'umi';
    import { MenuDataItem } from '@ant-design/pro-layout';
    import { query } from '@/services/menu';
    
    export interface MenuModelState {
        menuData: MenuDataItem[];
    }
    
    export interface MenuModelType {
        namespace: 'menu';
        state: MenuModelState;
        effects: {
            getMenuData: Effect;
        };
        reducers: {
            saveMenuData: Reducer<MenuModelState>;
        };
    }
    
    //这里做了个转换,可能服务端返回的接口格式和前端的路由格式并不一致,可以在这个方法里进行调整,这里的方法仅作参考,根据自己实际情况进行调整即可
    const menuFormatter = (response: any) => {
        if (response === null)
            return [];
    
        var re = response.map((item: { name: string; route: string; children: any; }) => {
            const result = {
                children: {},
                name: item.name,
                path: item.route === null ? '/' : item.route,
            };
    
            if (item.children) {
                result.children = menuFormatter(item.children);
            }
    
            return result;
        })
    
        return re;
    }
    
    const MenuModel: MenuModelType = {
        namespace: 'menu',
        state: {
            menuData: [],
        },
    
        effects: {
            *getMenuData(_, { put, call }) {
                const response = yield call(query);
                yield put({
                    type: 'saveMenuData',
                    payload: menuFormatter(response.data.viewMenu),
                });
            },
        },
    
        reducers: {
            saveMenuData(state, action) {
                return {
                    ...state,
                    menuData: action.payload || [],
                };
            },
        },
    };
    export default MenuModel;
    

    调整组件 BasicLayout.tsx

    antd pro的菜单调整在 src/layouts/BasicLayout.tsx 文件中

    这里menuDataRender 默认指向一个方法,我这里不要原来的方式,我们要调整成自己的数据

    以下代码如无特殊说明,都在 BasicLayout.tsx 文件中

    1. 调整接口

    在 BasicLayoutProps 接口中添加承载菜单的字段

    2. 调整组件传入的字段,useEfect方法中加入请求服务的路由

    3. 调整组件menuDataRender为使用传进来的菜单数据(以前那个方法不用了)

    4. 调整connect方法,获取数据

    menu是我们在models/menu.tx中定义的MenuModelState类型,光这里写会提示错误,我们需要在ConnectState中先将该字段定义才可以正常使用

    【运行一下试试效果】

    执行命令运行一下看看效果

    cnpm start
    

    可以看到,已经自动触发了后端接口,并获取到了数据,最后又用服务端的数据渲染了菜单

    其他内容可以参考官方文档

    antd pro官网地址:https://pro.ant.design/index-cn

  • 相关阅读:
    jQuery .css("width")和.width()的区别
    用jquery写一个滑动TAB 例子
    D
    4 Values whose Sum is 0
    Hibernate学习之hql 与sql
    BigDecimal进行精确运算
    Date类与SimpleDateFormat类中parse()方法和format()方法
    单例模式下的懒汉和饿汉模式
    Java中Date类型详解
    Spring @Column的注解详解
  • 原文地址:https://www.cnblogs.com/7tiny/p/13446188.html
Copyright © 2020-2023  润新知