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.效果及拿到的值