002 用React, Ant Design 重写Web端恒生交易日接口的图形化展示


title: 002 用React, Ant Design 重写Web端恒生交易日接口的图形化展示

上一节 001 在Windows,Mac,Linux中快速安装配置Node.js环境,并安装VSCode, 完成Web端恒生交易日接口的图形化展示 我们使用原生的HTML,CSS, JS,完成了恒生交易日接口图形化展示;

随着页面内容元素(DOM)的增多,原生JS操作页面内容元素代码就会越来越多,这些代码大多重复冗余且难以管理,即使我们使用jQuery这种封装了大量优秀方法的库,随着功能越来越多,读懂页面元素之间的交互逻辑,会越来越困难。

前端流行的React ,提供了操控页面元素的新思路,将页面显示内容改变视为状态的改变,程序员只编写改变状态的代码(setState),对页面内容元素的操作交由React完成, 有了React,我们就可以省掉操作DOM的代码了!

本文将从零开始,将上一节的前端页面,使用React重写一遍,同时会使用很流行的UI库Ant Design, 让页面更更精致。

最终效果

日期时间处理工具Moment简易教程

moment官方参考文档: https://momentjs.com/docs/
moment中文参考文档: http://momentjs.cn/docs/

可通过进入momen官网,打开开发者工具,直接运行以下代码,进行验证学习。

官网学习

  • 获取当前日期
moment().format("YYYY-MM-DD")
  • 显示日期格式转换

12/08/2021转换为 2021-12-08

moment("12/08/2021", "MM/DD/YYYY").format("YYYY-MM-DD")

显示日期格式转换

  • 获取2021年2月12日所在月的第一天和最后一天
## 第一天
let currency_date = "2021-02-21"
moment(currency_date, "YYYY-MM-DD").format("YYYY-MM")+"-01"
## 最后一天
let currency_date = "2021-02-21"
moment(moment(currency_date, "YYYY-MM-DD").add(1, "months").format("YYYY-MM")+"-01", "YYYY-MM-DD").add(-1, "days").format("YYYY-MM-DD")

第一天

最后一天

新建一个React项目

npx create-react-app learn-react-antd
cd learn-react-antd
npm start

参考文档:https://github.com/facebook/create-react-app

React项目启动成功

目录

在React 项目中,安装Ant Design

npm install antd

参考文档:https://ant.design/docs/react/use-with-create-react-app-cn

打开Ant Design文档,寻找合适的组件

Antd 组件们 https://ant.design/components/overview-cn/

Antd 日历组件 https://ant.design/components/calendar-cn/

选择组件

日历组件

阅读Ant Design文档,按照自身需求对组件进行改造

  • App.js 代码
import React, { useState, useEffect } from 'react';
import { DatePicker, PageHeader, Select, Calendar, Col, Row, Typography } from 'antd';
import moment from 'moment';
import Axios from 'axios';
import { } from 'antd';
import './App.css';
const { RangePicker } = DatePicker;

class App extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      start_date: moment('2019-09-01', 'YYYY-MM-DD'),
      end_date: moment('2019-09-30', 'YYYY-MM-DD'),
      calendar_value: moment('2019-09-01', 'YYYY-MM-DD'),
      secu_market: "71",
      tadingday_data: []

    }

    this.change_secu_market = this.change_secu_market.bind(this);
    this.get_data = this.get_data.bind(this);
    this.range_picker_change = this.range_picker_change.bind(this);
    this.onPanelChange = this.onPanelChange.bind(this);
    this.dateCellRender = this.dateCellRender.bind(this);

  }

  change_secu_market(secu_market) {
    this.setState({
      secu_market
    }, () => {
      this.get_data();
    })
  }

  range_picker_change(date_range) {
    this.setState({
      start_date: date_range[0],
      end_date: date_range[1]
    })
  }


  async get_data() {
    const tadingday_data = (await Axios({
      url: "http://localhost:3100/gildataastock/v1/commontable/tadingday",
      method: "GET",
      params: {
        "start_date": moment(this.state.start_date).format("YYYY-MM-DD"),
        "end_date": moment(this.state.end_date).format("YYYY-MM-DD"),
        "secu_market": this.state.secu_market
      }
    }))['data']['data']

    await new Promise((resolve, reject) => {

      this.setState({
        tadingday_data
      }, () => {
        console.log('获取数据成功==>>', tadingday_data);
        resolve(tadingday_data);
      })
    })

  }

  onPanelChange(value, mode) {

    console.log("value==>>", value, "mode==>>", mode);

    if (mode === "month") {
      const start_date = moment(moment(value).format("YYYY-MM") + "-01", "YYYY-MM-DD");

      const end_date = moment(moment(moment(value).add(1, 'month').format("YYYY-MM") + "-01").subtract(1, "days").format("YYYY-MM-DD"), "YYYY-MM-DD");

      const calendar_value = moment(value)

      console.log('==start_date==>>', start_date);

      console.log('==end_date==>>', end_date);

      this.setState({
        start_date,
        end_date,
        calendar_value
      }, async () => {
        await this.get_data();
      })
    }
  }

  dateCellRender(value) {
    let result = <div>{moment(value).format("DD")}</div>;
    const tadingday_data_json = {}
    this.state.tadingday_data.map((v) => [
      tadingday_data_json[v['trading_date']] = v
    ])


    if (tadingday_data_json[value.format("YYYY-MM-DD")] && tadingday_data_json[value.format("YYYY-MM-DD")]['if_trading_day'] === "是") {
      result = <div style={{ backgroundColor: '#1C7947', color: "#FFFFFF", textAlign: "right", padding: 2 }}>工 作</div>;
    }

    if (tadingday_data_json[value.format("YYYY-MM-DD")] && tadingday_data_json[value.format("YYYY-MM-DD")]['if_trading_day'] === "否") {

      result = <div style={{ backgroundColor: '#FFFD95', textAlign: "right", padding: 2 }}>休 息</div>;
    }

    return result;
  }

  componentDidMount() {
    this.get_data()
  }


  render() {
    return <div className="App">

      <Typography.Title style={{textAlign: "center"}} level={4}>交易日批量查询(React版) 恒生交易日历查询Demo</Typography.Title>
      <div style={{padding: 8}}>
        <Typography.Title level={4}>选择交易市场</Typography.Title>
        <Select style={{ width: "200px" }}
          defaultValue={this.state.secu_market}
          onChange={this.change_secu_market}
        >
          <option value="71" selected>柜台交易市场</option>
          <option value="72">香港联交所</option>
          <option value="77">美国纳斯达克证券交易所</option>
          <option value="83">沪深证券交易所</option>
          <option value="89">银行间债券市场</option>
        </Select>
      </div>


      <Calendar
        key={(this.state.tadingday_data.length > 0 ? (this.state.tadingday_data[0]['trading_date'] +this.state.tadingday_data[0]['secu_market'] + this.state.tadingday_data.length) : "0")}
        defaultValue={this.state.defualtValue}
        value={this.state.calendar_value}
        onPanelChange={this.onPanelChange}
        dateCellRender={this.dateCellRender}
        headerRender={({ value, type, onChange, onTypeChange }) => {
          const start = 0;
          const end = 12;
          const monthOptions = [];
          const current = value.clone();
          const localeData = value.localeData();
          const months = [];
          for (let i = 0; i < 12; i++) {
            current.month(i);
            months.push(localeData.monthsShort(current));
          }

          for (let index = start; index < end; index++) {
            monthOptions.push(
              <Select.Option className="month-item" key={`${index}`}>
                {months[index]}
              </Select.Option>,
            );
          }
          const month = value.month();

          const year = value.year();
          const options = [];
          for (let i = year - 10; i < year + 10; i += 1) {
            options.push(
              <Select.Option key={i} value={i} className="year-item">
                {i}
              </Select.Option>,
            );
          }
          return (
            <div style={{ padding: 8 }}>
              <Typography.Title level={4}>选择日期</Typography.Title>
              <Row gutter={8}>
                <Col>
                  <Select

                    dropdownMatchSelectWidth={false}
                    className="my-year-select"
                    onChange={newYear => {
                      const now = value.clone().year(newYear);
                      onChange(now);
                    }}
                    value={String(year)}
                  >
                    {options}
                  </Select>
                </Col>
                <Col>
                  <Select
                    dropdownMatchSelectWidth={false}
                    value={String(month)}
                    onChange={selectedMonth => {
                      const newValue = value.clone();
                      newValue.month(parseInt(selectedMonth, 10));
                      onChange(newValue);
                    }}
                  >
                    {monthOptions}
                  </Select>
                </Col>
              </Row>
            </div>
          );
        }}
      />
    </div>
  }
}

export default App;
  • App.scss代码
@import '~antd/dist/antd.css';

.App {
    width: 800px;
    margin: 20px auto;
}

验证最终效果

最终效果

本文永久更新地址(欢迎来读留言,写评论):

https://www.v2fy.com/p/2021-12-19-react-antd-1639896341000