鍍金池/ 問答/HTML/ react 三級聯(lián)動地區(qū)選擇組件 有木有

react 三級聯(lián)動地區(qū)選擇組件 有木有

項目急求,伸手黨小白求一個三級聯(lián)動地區(qū)選擇組件。

回答
編輯回答
寫榮
2018年3月4日 04:58
編輯回答
貓小柒

Ant Design Mobile 比較輕量。
https://mobile.ant.design/ind...

2017年3月6日 16:48
編輯回答
貓小柒

項目里正好有一個
clipboard.png

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import Selector from './selector';
import Model from '../model/model';
import * as API from '../constants/api';

class Location extends Component {
    static propTypes = {
        province: PropTypes.shape({
            id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
            name: PropTypes.string
        }),
        city: PropTypes.shape({
            id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
            name: PropTypes.string
        }),
        district: PropTypes.shape({
            id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
            name: PropTypes.string
        }),
        validating: PropTypes.bool, // 是否驗證location值得有效性
        static: PropTypes.bool,
        hasCode: PropTypes.bool,
        required: PropTypes.bool,
        onFetchProvinces: PropTypes.func,
        onFetchCities: PropTypes.func,
        onFetchDistricts: PropTypes.func,
        onChangeLocation: PropTypes.func,
        onError: PropTypes.func,
        onSetState: PropTypes.func
    }

    static defaultProps = {
        province: {},
        city: {},
        district: {},
        static: false,
        hasCode: false,
        onChangeLocation: () => {},
        onError: obj => alert(obj.message),
        onSetState: () => {}
    }

    constructor(props) {
        super(props);

        this.state = {
            provinces: [],
            cities: [],
            districts: []
        };

        this.initComponent(props);

        this.cacheData = {
            provinces: {},
            cities: {},
            districts: {}
        }
    }

    componentWillReceiveProps(nextProps) {
        const { province: nextProvince, city: nextCity, district: nextDistrict } = nextProps;
        const { province, city, district } = this.props;

        if (nextProvince && (!province || nextProvince.id !== province.id)) {
            const provincesCacheData = this.cacheData.provinces;
            const citiesCacheData = this.cacheData.cities;
            const nextProvinceId = nextProvince.id;

            if (citiesCacheData[nextProvinceId]) {
                const nextState = { cities: citiesCacheData[nextProvinceId].items };
                this.setState(nextState, () => this.props.onSetState(nextState));
            } else {
                this.handleFetchCities(nextProvinceId);
            }
        }

        if (nextCity && (!city || nextCity.id !== city.id)) {
            const citiesCacheData = this.cacheData.cities;
            const districtsCacheData = this.cacheData.districts;
            const nextProvinceId = nextProvince.id;
            const nextCityId = nextCity.id;

            if (districtsCacheData[`${nextProvinceId}_${nextCityId}`]) {
                const nextState = { districts: districtsCacheData[`${nextProvinceId}_${nextCityId}`].items };
                this.setState(nextState, () => this.props.onSetState(nextState));
            } else {
                this.handleFetchDistricts(nextProvinceId, nextCityId);
            }
        }
    }

    fetchProvinces = () => {
        return new Promise((resolve, reject) => {
            const model = Model.getInstance();
            model.url = API.API_FETCH_PROVINCES;
            // model.setParam({ countryId: CONSTANTS.CATEGORY_TYPE_COOKING });
            model.execute((data) => {
                resolve(data.data || []);
            }, (err) => {
                if ('status' in err && err.status === 0) {
                    this.props.onError({
                        status: 'error',
                        message: '獲取省份失敗'
                    });
                }
                reject();
            }, this);
        });
    }

    fetchCities = (provinceId, callback) => {
        return new Promise((resolve, reject) => {
            const model = Model.getInstance();
            model.url = API.API_FETCH_CITIES;
            model.setParam({ provinceId, hasCode: this.props.hasCode ? 1 : 0 });
            model.execute((data) => {
                const cities = [];
                for (const city of (data.data.dataList || [])) {
                    cities.push({ id: city.cityId, name: city.cityName, shouzimu: city.shouzimu });
                }
                resolve(cities);
            }, (err) => {
                if ('status' in err && err.status === 0) {
                    this.props.onError({
                        status: 'error',
                        message: '獲取城市失敗'
                    });
                }
                reject();
            }, this);
        });
    }

    fetchDistricts = (provinceId, cityId, callback) => {
        return new Promise((resolve, reject) => {
            const model = Model.getInstance();
            model.url = API.API_FETCH_DISTRICTS;
            model.setParam({ provinceId, cityId, hasCode: this.props.hasCode ? 1 : 0 });
            model.execute((data) => {
                resolve(data.data.dataList || []);
            }, (err) => {
                if ('status' in err && err.status === 0) {
                    this.props.onError({
                        status: 'error',
                        message: '獲取市縣失敗'
                    });
                }
                reject();
            }, this);
        });
    }

    handleSelectProvince = (provinceId) => {
        if (!this.props.province || provinceId !== this.props.province.id) {
            const provincesCacheData = this.cacheData.provinces;
            const citiesCacheData = this.cacheData.cities;

            if (citiesCacheData[provinceId]) {
                const nextState = { cities: citiesCacheData[provinceId].items };
                this.setState(nextState, () => this.props.onSetState(nextState));
            }

            const province = { id: provinceId, name: (provincesCacheData[provinceId] || {}).name };
            this.props.onChangeLocation({ province, city: null, district: null });
            this.setState({ districts: [] }, () => this.props.onSetState({ districts: [] }));
        }
    }

    handleSelectCity = (cityId) => {
        if (!this.props.city || cityId !== this.props.city.id) {
            const citiesCacheData = this.cacheData.cities;
            const districtsCacheData = this.cacheData.districts;
            const { province: { id: provinceId } } = this.props;

            if (districtsCacheData[`${provinceId}_${cityId}`]) {
                const nextState = { districts: districtsCacheData[`${provinceId}_${cityId}`].items };
                this.setState(nextState, () => this.props.onSetState(nextState));
            }

            const city = { id: cityId, name: (citiesCacheData[provinceId][cityId] || {}).name };
            this.props.onChangeLocation({ city, district: null });
        }
    }

    handleSelectDistrict = (districtId) => {
        const { province: { id: provinceId }, city: { id: cityId } } = this.props;
        const districtsCacheData = this.cacheData.districts;
        const district = { id: districtId, name: (districtsCacheData[`${provinceId}_${cityId}`][districtId] || {}).name };
        this.props.onChangeLocation({ district });
    }

    handleFetchProvinces = () => {
        const fetchProvinces = this.props.onFetchProvinces || this.fetchProvinces;
        fetchProvinces().then(provinces => {
            this.updatedProvincesToCache(provinces);
            const nextState = { provinces: this.cacheData.provinces.items };
            this.setState(nextState, () => this.props.onSetState(nextState));
        });
    }

    handleFetchCities = (provinceId) => {
        const fetchCities = this.props.onFetchCities || this.fetchCities;
        fetchCities(provinceId).then(cities => {
            this.updatedCitiesToCache(provinceId, cities);
            const nextState = { cities: this.cacheData.cities[provinceId].items };
            this.setState(nextState, () => this.props.onSetState(nextState));
        });
    }

    handleFetchDistricts = (provinceId, cityId) => {
        const fetchDistricts = this.props.onFetchDistricts || this.fetchDistricts;
        fetchDistricts(provinceId, cityId).then(districts => {
            this.updatedDistrictsToCache(provinceId, cityId, districts);
            const nextState = { districts: this.cacheData.districts[`${provinceId}_${cityId}`].items };
            this.setState(nextState, () => this.props.onSetState(nextState));
        });
    }

    initComponent = (props) => {
        const { province, city, district } = props;
        this.handleFetchProvinces();

        if (province.id) {
            this.handleFetchCities(province.id);

            if (city.id) {
                this.handleFetchDistricts(province.id, city.id);
            }
        }
    }

    validateProvince = () => {
        const { province } = this.props;

        return province && province.id;
    }

    validateCity = () => {
        const { city } = this.props;

        return (city && city.id) || (this.validateProvince() && (!this.state.cities || !this.state.cities.length) && (!city || !city.id));
    }

    validateDistrict = () => {
        const { district } = this.props;

        return (district && district.id) || (this.validateCity() && (!this.state.districts || !this.state.districts.length) && (!district || !district.id));
    }

    updatedProvincesToCache = (provinces) => {
        this.cacheData.provinces = {};
        const provincesCacheData = this.cacheData.provinces;
        for (const province of (provinces || [])) {
            provincesCacheData[province.id] = {
                name: province.name,
                cities: {}
            };
        }
        provincesCacheData.items = provinces;
    }

    updatedCitiesToCache = (provinceId, cities) => {
        const citiesCacheData = {};
        const items = [];

        for (const city of (cities || [])) {
            citiesCacheData[city.id] = {
                name: city.name,
                shouzimu: city.shouzimu,
                districts: {}
            };
            items.push({ ...city });
        }
        citiesCacheData.items = items;
        this.cacheData.cities[provinceId] = citiesCacheData;
    }

    updatedDistrictsToCache = (provinceId, cityId, districts) => {
        const districtsCacheData = {};
        const items = [];

        for (const district of (districts || [])) {
            districtsCacheData[district.id] = {
                name: district.name
            };
            items.push({ ...district });
        }
        districtsCacheData.items = items;
        this.cacheData.districts[`${provinceId}_${cityId}`] = districtsCacheData
    }

    render() {
        const province = this.props.province || {};
        const city = this.props.city || {};
        const district = this.props.district || {};
        const { provinces, cities, districts } = this.state;
        const { validating } = this.props;

        const isProvinceValid = this.validateProvince();
        const isCityValid = this.validateCity();
        const isDistrictValid = this.validateDistrict();

        return (
            <div className="mw-location">
                <div className="mw-location-column mw-location-provinces">
                    <Selector
                        className={classNames('mw-form-control', { error: !!validating && !isProvinceValid })}
                        value={province.id}
                        options={provinces}
                        valueField="id"
                        labelField="name"
                        placeholder="請選擇省份"
                        onChange={this.handleSelectProvince}
                    />
                </div>
                <div className="mw-location-column mw-location-cities">
                    <Selector
                        className={classNames('mw-form-control', { error: !!validating && !isCityValid })}
                        value={city.id}
                        options={cities}
                        valueField="id"
                        labelField="name"
                        placeholder="請選擇城市"
                        onChange={this.handleSelectCity}
                    />
                </div>
                <div className="mw-location-column mw-location-districts">
                    <Selector
                        className={classNames('mw-form-control', { error: !!validating && !isDistrictValid })}
                        value={district.id}
                        options={districts}
                        valueField="id"
                        labelField="name"
                        placeholder="請選擇區(qū)縣"
                        onChange={this.handleSelectDistrict}
                    />
                </div>
            </div>
        );
    }
}

export default Location;
2018年3月20日 08:53
編輯回答
亮瞎她
        <Picker
            mode='date'
            title='選擇血站'
            cols={2} //  顯示2列 二級聯(lián)動
            data={bloodcenter} // 血液中心全國地址 (放進你需要的城市三級聯(lián)動,按照規(guī)定的格式)
            {...getFieldProps('donationLocation', {
              rules: [{ required: true, message: '選擇血站' }],
              initialValue: this.state.donationLocation, // 默認選擇深圳
              onChange (value) {
                slef.setState({
                  donationLocation: value
                })
              }
            })}
          >
            <Item arrow='horizontal'>上次獻血地點</Item>
          </Picker>

用的是ant-design-mobile 中的插件 你可以參考一下 全國三級聯(lián)動我這邊寫了一個js直接轉(zhuǎn)換成了ant需要的格式

2017年1月12日 08:25