1. 程式人生 > >Dva 使用antd的Cascader動態獲取樹形省市區聯級選擇框的完整元件

Dva 使用antd的Cascader動態獲取樹形省市區聯級選擇框的完整元件

效果圖:

就是實現這樣的,選擇框的時候,將向後臺請求省的資料,當點選省的時候,就會請求當前點選市的資料 。。。。,請求的介面只有一個,傳值為code值。樹形的資料。

完整的元件程式碼:

import React, { Component } from 'react';

import { Cascader, message } from 'antd';

import _ from 'lodash';

import { isSuccess } from 'utils';

import styles from './area.less'

import { queryArea } from './service';

let options = [];

const areaChildrenMap = {};

let functions = [];

const municipality = ['北京市', '上海市', '天津市', '重慶市', '香港特別行政區', '澳門特別行政區', ];

async function getData(value) {

    let target = null;

    let val = [];

    let code = 0;

    if (value && value.length) {

        val = value.concat();

        target = val.pop();

        code = target.code;

    }

    const isLeaf = !!target && (municipality.includes(target.label) || value.length > 1);

    const tem = val.length ? val.pop().value : 0;

    await getDataByCode(code, isLeaf, areaChildrenMap[tem], target);

}

// 訂閱資料更改

function subscribe(callback) {

    functions.push(callback);

}

// 取消訂閱

function unsubscribe(callback) {

    functions = functions.filter(fun => fun !== callback);

}

async function getCodes(labels, list) {

    const label = labels.shift();

    const target = list.find(l => l.label === label);

    if (!target) return [];

    const code = target.code;

    let arr = [code];

    if (!labels.length) return arr;

    if (!areaChildrenMap[code]) {

        if (target.code.toString().slice(2, 6) == '0000' && !municipality.includes(target.name)) {

            await getDataByCode(code, true, list);

        } else {

            await getDataByCode(code, true, list);

        }

    }

    arr = arr.concat(await getCodes(labels, areaChildrenMap[code]));

    return arr;

}

async function getDataByCode(code, isLeaf, list, target) {

    const res = await queryArea(code);

    target ? target.loading = false : null;

    if (isSuccess(res)) {

        res.data.forEach(d => {

            d.value = d.code;

            d.label = d.name;

            d.isLeaf = isLeaf;

        });

        areaChildrenMap[code] = res.data;

        if (!code) { // 第一層

            options = res.data;

        } else {

            res.data.length && list.forEach(d => d.code === code ? d.children = res.data : null);

        }

        functions.forEach(fun => fun());

    } else {

        message.error(res.message);

    }

}

getData();// 獲取第一層

class AreaSelect extends Component {

    constructor(props, context) {

        super(props, context);

        this.state = {

            value: [],

            labels: [],

            options,

        };

    }

    componentWillMount() {

        subscribe(this.update);

    }

    componentWillReceiveProps(nextProps) {

        if (!nextProps.visible) {

            this.setState({ value: [] });

        }

        if (nextProps.value && nextProps.value !== this.state.value) {

            this.setValue(nextProps.value);

        }

    }

    componentWillUnmount() {

        unsubscribe(this.update);

    }

    onChange = (value, selectedOptions) => {

const { onChange } = this.props;

        let labels = selectedOptions.map(o => o.label);

        value = value.concat(new Array(3 - value.length).fill(''));

        labels = labels.concat(new Array(3 - labels.length).fill(''));

this.setState({ value, labels });

        onChange ? onChange(labels) : null;

    }

    async setValue(value, key, callback) {

        if (!value.length) {

            this.setState({ value: [], labels: [] }, callback);

            return;

        }

        if (value.length < 3) value = value.slice(0, 2);

        if (key === 'code') this.setState({ value }, callback);

        else {

            this.setState({ labels: value });

            const val = await getCodes(value.concat(), options);

            this.setState({ value: val }, callback);

        }

    }

    getValue(key) {

        if (key === 'code') return this.state.value.concat();

        else return this.state.labels.concat();

    }

    update = () => {

        this.setState({ options: options.concat() });

    }

    loadData = async (selectedOptions) => {

        const targetOption = selectedOptions[selectedOptions.length - 1];

        targetOption.loading = true;

        await getData(selectedOptions);

    }

    render() {

        const { ...props } = this.props;

        return (

            <div className={styles.wrapper}>

                <Cascader

                    {...props}

                    options={this.state.options}

                    onChange={this.onChange}

                    loadData={this.loadData}

value={this.state.value}

placeholder="請選擇省市"

                    changeOnSelect

                />

            </div>

        );

    }

}

export default AreaSelect;

isSuccess 的方法程式碼:

const error = {

  success: {

    code: '200',

    message: '請求成功',

  },

};

export function isSuccess(res) {

  if (!res) return false;

  const tem = res.code === error.success.code;

  return tem;

}

queryArea:這是省市區的資料介面

使用方法:在需要的地方引入元件:<AreaSelect onChange={handleChangeAddress}/>