react 结合 antd 的 Cascader 组件实现 pc 端选择城市控件

业务需求,网上找了好多,发现都不太满意,于是自己写了一个

1.实现如下

提示:
数据地址点击 https://xf-1252186245.cos.ap-chengdu.myqcloud.com/data/data.js,复制下来放到组件同级目录,命名 data.js 就好

依赖: react antd rc-form prop-types 等, 先安装依赖,步骤略。

CitySelect.jsx 文件

1
import React, { Component } from "react";
2
import { createForm } from "rc-form";
3
import { Cascader } from "antd";
4
import city from "./data"; //  数据见上提示
5
import PropTypes from "prop-types";
6
7
//先配置修饰器 没有配置的话用把 @createForm()删掉
8
//然后把最后一行 export default CitySelect;  换成 export default createForm()(CitySelect)
9
@createForm()
10
class CitySelect extends Component {
11
  // props类型检查
12
  static propTypes = {
13
    //  监听选择
14
    onChange: PropTypes.func,
15
    // 获取选择值
16
    getSelectedValues: PropTypes.func,
17
    // 默认值
18
    value: PropTypes.array
19
  };
20
21
  onCascaderChange = selectedValues => {
22
    const { onChange, getSelectedValues } = this.props;
23
    const result = [];
24
    // 递归查询城市所有数据
25
    function findCityData(city) {
26
      city.forEach(item => {
27
        const { id, label, value, children } = item;
28
        if (selectedValues.includes(value)) {
29
          result.push({ id, label, value });
30
        }
31
        if (children && children.length) {
32
          findCityData(children);
33
        }
34
      });
35
    }
36
    findCityData(city);
37
38
    // 分发监听
39
    onChange && onChange(selectedValues);
40
    getSelectedValues && getSelectedValues(result);
41
  };
42
43
  componentDidMount() {
44
    const {
45
      form: { setFieldsValue },
46
      value: selectedValues
47
    } = this.props;
48
49
    if (!selectedValues || !selectedValues.length) {
50
      return;
51
    }
52
53
    const result = [];
54
    // 递归查询城市名称数据
55
    function findLabel(children) {
56
      children.forEach(item => {
57
        const { label, value, children } = item;
58
        if (selectedValues.includes(label)) {
59
          result.push(value);
60
        }
61
        if (children && children.length) {
62
          findLabel(children);
63
        }
64
      });
65
    }
66
    // 卡省份解决县或市名称一样的问题
67
    city.forEach(item => {
68
      const { label, value, children } = item;
69
      if (selectedValues.includes(label)) {
70
        result.push(value);
71
        if (children && children.length) {
72
          findLabel(children);
73
        }
74
      }
75
    });
76
    // 设置默认值
77
    setFieldsValue({ city: result });
78
  }
79
80
  render() {
81
    const { getFieldProps } = this.props.form;
82
    return (
83
      <div>
84
        <Cascader
85
          options={city}
86
          {...getFieldProps("city", {
87
            onChange: this.onCascaderChange,
88
            rules: [{ required: true }]
89
          })}
90
          placeholder="请选择城市"
91
        />
92
      </div>
93
    );
94
  }
95
}
96
97
export default CitySelect;

2.使用

1
import React, { Component } from "react";
2
import { Form, Button, message, Icon } from "antd";
3
4
import CitySelect from "@/components/CitySelect";
5
6
import "./hotel.less";
7
8
const FormCreate = Form.create;
9
const FormItem = Form.Item;
10
11
@FormCreate()
12
class HotelSetting extends Component {
13
  state = {
14
    selectedValues: []
15
  };
16
17
  handleReset = () => {
18
    this.props.form.resetFields();
19
  };
20
21
  // 获取选择值
22
  getSelectedValues = selectedValues => {
23
    this.setState({
24
      selectedValues
25
    });
26
  };
27
28
  handleSumit = e => {
29
    const { form } = this.props;
30
31
    e.preventDefault();
32
    form.validateFields((err, formData) => {
33
      console.log(formData, "formData");
34
      if (err) {
35
        message.destroy();
36
        return message.warning("请完整填写表单");
37
      }
38
      const data = {
39
        ...formData,
40
        selectedValues: this.state.selectedValues
41
      };
42
      console.log(data, "data");
43
    });
44
  };
45
46
  render() {
47
    const { getFieldDecorator } = this.props.form;
48
49
    const defaultCity = ["陕西省", "西安市", "碑林区"];
50
51
    return (
52
      <Form
53
        className="custom-form custom-vertical-hotel-form"
54
        layout="vertical"
55
        labelAlign="left"
56
        onSubmit={e => {
57
          this.handleSumit(e);
58
        }}
59
        style={{ background: "#fff", padding: 24 }}
60
      >
61
        {/* 数据绑定 拿到的city字段是城市编码  getSelectedValues监听可以拿到选择的数据对象 */}
62
        <FormItem label="城市选择:">
63
          {getFieldDecorator("city", {
64
            initialValue: defaultCity,
65
            rules: [{ required: true, message: "请选择城市选择" }]
66
          })(<CitySelect getSelectedValues={this.getSelectedValues} />)}
67
        </FormItem>
68
69
        <FormItem label="城市选择:">
70
          <CitySelect
71
            getSelectedValues={this.getSelectedValues}
72
            value={defaultCity}
73
          />
74
        </FormItem>
75
76
        <FormItem style={{ paddingBottom: 0 }}>
77
          <Button type="primary" htmlType="submit">
78
            <Icon type="arrow-up" />
79
            保存
80
          </Button>
81
        </FormItem>
82
      </Form>
83
    );
84
  }
85
}
86
87
export default HotelSetting;

hotel.less

1
:global(.custom-vertical-hotel-form .ant-form-item-label) {
2
  width: 90px;
3
4
  vertical-align: top;
5
}
6
:global(.custom-vertical-hotel-form .ant-form-item-control-wrapper) {
7
  width: 340px;
8
  display: inline-block;
9
}

3.效果及拿到的值

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述