最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • React后台管理前端系统(基于开源框架开发)起步式

    正文概述 掘金(Fizz在掘金38275)   2021-02-22   848

    写博客不容易,如果对你有帮助请点个赞吧。有时间的可以评论一下。        这个系统的搭建背景是这样的,有一个朋友想看到现有系统中的一些,用户数据,新闻数据,只需要看到,短期不需要增删改功能,让我搭建一个简单的后台系统给他看.接到任务作为一个有四年开发经验的人来说这也太简单了吧,开始干吧,最简单的办法是直接使用开源项目github.com/PanJiaChen/…下载下来,把不要的路由去掉,新建几个表格路由,页面直接复制过来就用了.

          这样算下来,整个系统搭建时间不会超过半天,而且这个开源框架我已经玩的很溜了,后期开发完全不费事.但是,这个方案被我拒绝了。为什么那?因为我想跳出舒适区.接受更大的挑战,目前和vue并驾齐驱的React项目也很流程,很多公司也在使用.于是乎,技术栈就是用React了。但是要从零搭建,时间上划不来,因为需要集成很多东西,基础建设就要耗费很长时间.于是乎在GitHub上一顿搜,Ok 找到了二个比较可靠的项目使用,一个是 ant-design-pro 另一个是antd-admin 二个项目大同小异, 使用的技术栈react,ant-design,dva,Mock  基于 Antd UI 设计语言  虽然我对dva和ant-design 了解不深,但我还是准备挑战一下.不入虎穴焉得虎子.

      一开始我选择的是antd-admin 因为代码比较规范,UI也比较符合我的审美.开始做吧

     首先找到一个列表页,仔细阅读代码,弄清楚依赖关系,然后新建一个目录,把列表页的相关文件都拷贝进去, 配路由,设置权限.

    但是在调取接口的时候,接口虽然调取了,但是页面没有刷新出来,怎么调试都不出来,急死了.最后只好需求同事的帮助,但是他们也很少有人用React.就这样过了一天,我决定先把问题放一下, 问题的答案肯定就在代码里,先休息一下,别被这个问题让自己的眼光太局限,导致看不到问题的本质.在这个问题还没有解决的情况下,我又开始了另一个项目 ant-design-pro的尝试.因为我知道,那个页面没有显示数据的问题,我肯定会解决的,只是时间问题,当我解决了,肯定会觉得自己当时太笨了,后来的进展证明确实是这样.

      在数据不显示的问题上短暂停留下,我开始探索ant-design-pro

      这里我来说一下,当一个菜鸟接手一个新项目时遇到的迷茫和问题。

     首先项目开启我们会看到页面的URL,URL与我们的页面是一一对应的,意思就是我们根据URL可以再项目中准确地找到对应的页面,或页面入口.当然页面可能会一个主页面,多个子页面.这里忘记说一点,URL对应页面 这种对应关系的配置,叫做路由.

    看到URL,就能找到路由,就能找到页面, 找到页面就完成了项目熟悉的第一步, 到了这一步,你就能自己写个静态页面,自己配个路由就能在浏览器看到了. 是不是很简单.这是大致的思路.不过有的框架有权限拦截,新的页面路由可能需要给登录的人赋权限才能出现. 等下我会以具体页面案例来做个演示.

    第一步已经学会了,接下来就是进入到页面内,看看页面的数据是怎么流转的,事件,参数是怎么配置的.这一块是比较难的,也是熟悉前端项目的核心知识点.敲重点,重点,重点 一般一个页面,都会有初始化函数, 比如一个vue组件会在mounted状态下调取获取数据的接口,来渲染页面.React会在componentDidMount生命周期调取获取数据的接口. 每个页面或组件都有可能是两个或更多个组件,组合而来的,而组件的参数也是错综复杂,组件的表现,事件都是有这些参数控制的.除了简单理解这些参数,还需要理解这些组件是怎么组合起来的.

    说也说了够多的 下面我就用一个列表页来给你看一下 我是怎么了解一个前端项目和开发的

    我以ant-design-pro的查询表格页面为例子 React后台管理前端系统(基于开源框架开发)起步式

    我们拿着/list/table-list这个路由去项目中搜索  React后台管理前端系统(基于开源框架开发)起步式 打开这个文件  React后台管理前端系统(基于开源框架开发)起步式

    很明显这个文件是路由管理  这里清楚的写着 /list/table-list路由指向文件../routes/List/TableList

    其中代码中的

    dynamicWrapper(app, ['rule'], ()
    

    我们暂时不需要去理解他的意思,因为我们的第一步是根据路由找到对应的页面. 而不是去理解每一行代码.

    打开../routes/List/TableList我们看到 React后台管理前端系统(基于开源框架开发)起步式

    果然是我们要寻找的页面, 改一二个文字 刷新一下页面,果然改变了.好开心.第一步就这样完了.

    必须要提的全局搜索是一个非常很好的技能,大家一定要学会.另外 搜素路由的时候,有的路由是分开写的,比如路由/list/table-list 是有/list 和/table-list 直接搜/list/table-list搜不到,这个时候你就要去尝试单个搜索了,交叉比对,或者,找像路由配合的目录 这是一个简单实用的方法.走到这一步,你就可以自己去创建一个页面,配一个路由看看了.

    接下来说一下进入页面内部改如何快速理解页面大致结构

    import React, { PureComponent, Fragment } from 'react';
    import { connect } from 'dva';
    import moment from 'moment';
    import {
      Row,
      Col,
      Card,
      Form,
      Input,
      Select,
      Icon,
      Button,
      Dropdown,
      Menu,
      InputNumber,
      DatePicker,
      Modal,
      message,
      Badge,
      Divider,
    } from 'antd';
    import StandardTable from 'components/StandardTable';
    import PageHeaderLayout from '../../layouts/PageHeaderLayout';
    
    import styles from './TableList.less';
    
    const FormItem = Form.Item;
    const { Option } = Select;
    const getValue = obj =>
      Object.keys(obj)
        .map(key => obj[key])
        .join(',');
    const statusMap = ['default', 'processing', 'success', 'error'];
    const status = ['关闭', '运行中', '已上线', '异常'];
    
    const CreateForm = Form.create()(props => {
      const { modalVisible, form, handleAdd, handleModalVisible } = props;
      const okHandle = () => {
        form.validateFields((err, fieldsValue) => {
          if (err) return;
          form.resetFields();
          handleAdd(fieldsValue);
        });
      };
      return (
        <Modal
          
          visible={modalVisible}
          onOk={okHandle}
          onCancel={() => handleModalVisible()}
        >
          <FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="描述">
            {form.getFieldDecorator('desc', {
              rules: [{ required: true, message: 'Please input some description...' }],
            })(<Input placeholder="请输入" />)}
          </FormItem>
        </Modal>
      );
    });
    
    @connect(({ rule, loading }) => ({
      rule,
      loading: loading.models.rule,
    }))
    @Form.create()
    export default class TableList extends PureComponent {
      state = {
        modalVisible: false,
        expandForm: false,
        selectedRows: [],
        formValues: {},
      };
    
      componentDidMount() {
        const { dispatch } = this.props;
        dispatch({
          type: 'rule/fetch',
        });
      }
    
      handleStandardTableChange = (pagination, filtersArg, sorter) => {
        const { dispatch } = this.props;
        const { formValues } = this.state;
    
        const filters = Object.keys(filtersArg).reduce((obj, key) => {
          const newObj = { ...obj };
          newObj[key] = getValue(filtersArg[key]);
          return newObj;
        }, {});
    
        const params = {
          currentPage: pagination.current,
          pageSize: pagination.pageSize,
          ...formValues,
          ...filters,
        };
        if (sorter.field) {
          params.sorter = `${sorter.field}_${sorter.order}`;
        }
    
        dispatch({
          type: 'rule/fetch',
          payload: params,
        });
      };
    
      handleFormReset = () => {
        const { form, dispatch } = this.props;
        form.resetFields();
        this.setState({
          formValues: {},
        });
        dispatch({
          type: 'rule/fetch',
          payload: {},
        });
      };
    
      toggleForm = () => {
        const { expandForm } = this.state;
        this.setState({
          expandForm: !expandForm,
        });
      };
    
      handleMenuClick = e => {
        const { dispatch } = this.props;
        const { selectedRows } = this.state;
    
        if (!selectedRows) return;
    
        switch (e.key) {
          case 'remove':
            dispatch({
              type: 'rule/remove',
              payload: {
                no: selectedRows.map(row => row.no).join(','),
              },
              callback: () => {
                this.setState({
                  selectedRows: [],
                });
              },
            });
            break;
          default:
            break;
        }
      };
    
      handleSelectRows = rows => {
        this.setState({
          selectedRows: rows,
        });
      };
    
      handleSearch = e => {
        e.preventDefault();
    
        const { dispatch, form } = this.props;
    
        form.validateFields((err, fieldsValue) => {
          if (err) return;
    
          const values = {
            ...fieldsValue,
            updatedAt: fieldsValue.updatedAt && fieldsValue.updatedAt.valueOf(),
          };
    
          this.setState({
            formValues: values,
          });
    
          dispatch({
            type: 'rule/fetch',
            payload: values,
          });
        });
      };
    
      handleModalVisible = flag => {
        this.setState({
          modalVisible: !!flag,
        });
      };
    
      handleAdd = fields => {
        const { dispatch } = this.props;
        dispatch({
          type: 'rule/add',
          payload: {
            description: fields.desc,
          },
        });
    
        message.success('添加成功');
        this.setState({
          modalVisible: false,
        });
      };
    
      renderSimpleForm() {
        const { form } = this.props;
        const { getFieldDecorator } = form;
        return (
          <Form onSubmit={this.handleSearch} layout="inline">
            <Row gutter={{ md: 8, lg: 24, xl: 48 }}>
              <Col md={8} sm={24}>
                <FormItem label="规则编号">
                  {getFieldDecorator('no')(<Input placeholder="请输入" />)}
                </FormItem>
              </Col>
              <Col md={8} sm={24}>
                <FormItem label="使用状态">
                  {getFieldDecorator('status')(
                    <Select placeholder="请选择" style={{ width: '100%' }}>
                      <Option value="0">关闭</Option>
                      <Option value="1">运行中</Option>
                    </Select>
                  )}
                </FormItem>
              </Col>
              <Col md={8} sm={24}>
                <span className={styles.submitButtons}>
                  <Button type="primary" htmlType="submit">
                    查询
                  </Button>
                  <Button style={{ marginLeft: 8 }} onClick={this.handleFormReset}>
                    重置
                  </Button>
                  <a style={{ marginLeft: 8 }} onClick={this.toggleForm}>
                    展开 <Icon type="down" />
                  </a>
                </span>
              </Col>
            </Row>
          </Form>
        );
      }
    
      renderAdvancedForm() {
        const { form } = this.props;
        const { getFieldDecorator } = form;
        return (
          <Form onSubmit={this.handleSearch} layout="inline">
            <Row gutter={{ md: 8, lg: 24, xl: 48 }}>
              <Col md={8} sm={24}>
                <FormItem label="规则编号">
                  {getFieldDecorator('no')(<Input placeholder="请输入" />)}
                </FormItem>
              </Col>
              <Col md={8} sm={24}>
                <FormItem label="使用状态">
                  {getFieldDecorator('status')(
                    <Select placeholder="请选择" style={{ width: '100%' }}>
                      <Option value="0">关闭</Option>
                      <Option value="1">运行中</Option>
                    </Select>
                  )}
                </FormItem>
              </Col>
              <Col md={8} sm={24}>
                <FormItem label="调用次数">
                  {getFieldDecorator('number')(<InputNumber style={{ width: '100%' }} />)}
                </FormItem>
              </Col>
            </Row>
            <Row gutter={{ md: 8, lg: 24, xl: 48 }}>
              <Col md={8} sm={24}>
                <FormItem label="更新日期">
                  {getFieldDecorator('date')(
                    <DatePicker style={{ width: '100%' }} placeholder="请输入更新日期" />
                  )}
                </FormItem>
              </Col>
              <Col md={8} sm={24}>
                <FormItem label="使用状态">
                  {getFieldDecorator('status3')(
                    <Select placeholder="请选择" style={{ width: '100%' }}>
                      <Option value="0">关闭</Option>
                      <Option value="1">运行中</Option>
                    </Select>
                  )}
                </FormItem>
              </Col>
              <Col md={8} sm={24}>
                <FormItem label="使用状态">
                  {getFieldDecorator('status4')(
                    <Select placeholder="请选择" style={{ width: '100%' }}>
                      <Option value="0">关闭</Option>
                      <Option value="1">运行中</Option>
                    </Select>
                  )}
                </FormItem>
              </Col>
            </Row>
            <div style={{ overflow: 'hidden' }}>
              <div style={{ float: 'right', marginBottom: 24 }}>
                <Button type="primary" htmlType="submit">
                  查询
                </Button>
                <Button style={{ marginLeft: 8 }} onClick={this.handleFormReset}>
                  重置
                </Button>
                <a style={{ marginLeft: 8 }} onClick={this.toggleForm}>
                  收起 <Icon type="up" />
                </a>
              </div>
            </div>
          </Form>
        );
      }
    
      renderForm() {
        const { expandForm } = this.state;
        return expandForm ? this.renderAdvancedForm() : this.renderSimpleForm();
      }
    
      render() {
        const {
          rule: { data },
          loading,
        } = this.props;
        const { selectedRows, modalVisible } = this.state;
    
        const columns = [
          {
            title: '规则编号',
            dataIndex: 'no',
          },
          {
            title: '描述',
            dataIndex: 'description',
          },
          {
            title: '服务调用次数',
            dataIndex: 'callNo',
            sorter: true,
            align: 'right',
            render: val => `${val} 万`,
            // mark to display a total number
            needTotal: true,
          },
          {
            title: '状态',
            dataIndex: 'status',
            filters: [
              {
                text: status[0],
                value: 0,
              },
              {
                text: status[1],
                value: 1,
              },
              {
                text: status[2],
                value: 2,
              },
              {
                text: status[3],
                value: 3,
              },
            ],
            onFilter: (value, record) => record.status.toString() === value,
            render(val) {
              return <Badge status={statusMap[val]} text={status[val]} />;
            },
          },
          {
            title: '更新时间',
            dataIndex: 'updatedAt',
            sorter: true,
            render: val => <span>{moment(val).format('YYYY-MM-DD HH:mm:ss')}</span>,
          },
          {
            title: '操作',
            render: () => (
              <Fragment>
                <a href="">配置</a>
                <Divider type="vertical" />
                <a href="">订阅警报</a>
              </Fragment>
            ),
          },
        ];
    
        const menu = (
          <Menu onClick={this.handleMenuClick} selectedKeys={[]}>
            <Menu.Item key="remove">删除</Menu.Item>
            <Menu.Item key="approval">批量审批</Menu.Item>
          </Menu>
        );
    
        const parentMethods = {
          handleAdd: this.handleAdd,
          handleModalVisible: this.handleModalVisible,
        };
    
        return (
          <PageHeaderLayout >
            <Card bordered={false}>
              <div className={styles.tableList}>
                <div className={styles.tableListForm}>{this.renderForm()}</div>
                <div className={styles.tableListOperator}>
                  <Button icon="plus" type="primary" onClick={() => this.handleModalVisible(true)}>
                    新建
                  </Button>
                  {selectedRows.length > 0 && (
                    <span>
                      <Button>批量操作</Button>
                      <Dropdown overlay={menu}>
                        <Button>
                          更多操作 <Icon type="down" />
                        </Button>
                      </Dropdown>
                    </span>
                  )}
                </div>
                <StandardTable
                  selectedRows={selectedRows}
                  loading={loading}
                  data={data}
                  columns={columns}
                  onSelectRow={this.handleSelectRows}
                  onChange={this.handleStandardTableChange}
                />
              </div>
            </Card>
            <CreateForm {...parentMethods} modalVisible={modalVisible} />
          </PageHeaderLayout>
        );
      }
    }
    
    

    以这个页面为例

    第一次阅读代码我们一定要按照从上到下的顺序阅读,记住 是第一次.第一次第一次

    首先这个文件引入了几个组件 React dva moment antd  .....

    我们要对这个库或组件有个大致印象,比如我们要在页面修改antd 的Dropdown组件,就要去antd官文看看有那些参数可以调整.

    其他组件和工具库都是这样.假如你把页面头部的import 的东西有了大致了解,就继续往下看.

    页面有const 定义了一个方法,或一系列对象,这个对象有的是作为组件的参数 有的本身就是小子组件

     但我们看到这段代码时就要特别注意了

    componentDidMount() {
     const { dispatch } = this.props;
     dispatch({
       type: 'rule/fetch',
     });
    }
    

    在React组件的componentDidMount生命周期时 执行了

    dispatch({
     type: 'rule/fetch',
    });
    

    获取你不知道dva 或许你根本看不懂这段代码,但是你可以想象他到底是什么意思.有什么作用. 或者你直接删掉这段代码,看看页面有什么变化. 了解代码效果最简单最明了的方法是 直接删掉,看看报什么错,或有什么变化...O(∩_∩)O哈哈~虽然不是什么好方法,但是简单易用.到这里 你大概知道 这段代码大概就是去调取接口获取数据渲染到页面的.这种写法可能与我们平时写的不一样

    我们平时调取接口大概是这样的

    copyrightTypeList().then(res => {
      if (res.data.code === 0) {
        this.caseTypeList = res.data.data
      }
    })
    

    少年不要迷茫了,要接受改变.学习新的知识吧,跳出你的舒适区.

    dispatch({ type: 'rule/fetch', }); 这段代码的关键字是rule/fetch 要先在页面仔细搜索关于rule和fetch相关的代码.

    在搜素了很久我终于好到 rule是在那里 React后台管理前端系统(基于开源框架开发)起步式 ......文章到这里就吿一段落了 剩余的就好理解了

    属性一个项目还有一个方法就是打开项目的package.json 将里面的包 挨个查一遍,了解每个包的作用,用法.这也不失为一种好的快速上手的方法

    谢谢阅读.如果觉得对你有帮助请记得点赞或收藏.欢迎留言讨论.谢谢.


    起源地下载网 » React后台管理前端系统(基于开源框架开发)起步式

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元