vue2+Element-ui中使用级联选择器选择地区

vue2+Element-ui中使用级联选择器选择地区


效果

在这里插入图片描述

一、准备工作

  • 安装库
"china-division": "^2.7.0"
 
yarn add china-division

二、代码

①:级联选择

<el-cascader
                            v-model="valueData"
                            :props="cascaderProps"
                            :options="options"
                            placeholder="请选择家庭住址"
                            :disabled="false"
                            :clearable="true"
                            expandTrigger="hover"
                            separator='/'
                            ref="Cascader"`在这里插入代码片`
                            style="width: 100%;"
                            @change="handleChange"
                            @expand-change="expandChange"
                        ></el-cascader>

②:页面引入数据


import provinces from 'china-division/dist/provinces.json';
import cities from 'china-division/dist/cities.json';
import areas from 'china-division/dist/areas.json';
import streets from 'china-division/dist/streets.json';
import villages from 'china-division/dist/villages.json';

③:页面data数据(响应数据)

 valueData: [],
            cascaderProps: {
                value: 'code',
                label: 'name',
                children: 'children',
                emitPath: true,
                lazy: true,
                lazyLoad: this.lazyLoad,
                checkStrictly: true,
            },
            options: [],

④:页面方法


        loadProvinces() {
            const provincesData = provinces.map(province => ({
                code: province.code,
                name: province.name,
            }));
            this.options = provincesData;

        },
        lazyLoad(node, resolve) {
            const {level, value} = node;
            console.log(level, value)
            let children = [];

            switch (level) {
                case 1:
                    children = this.formatData(cities.filter(city => city.provinceCode === value));
                    break;
                case 2:
                    children = this.formatData(areas.filter(area => area.cityCode === value));
                    break;
                case 3:
                    children = this.formatData(streets.filter(street => street.areaCode === value));
                    break;
                case 4:
                    children = this.formatData(villages.filter(street => street.streetCode === value));
                    break;
            }
            if (children && children.length > 0) {
                resolve(children);
            } else {
                resolve()
            }
        },
        formatData(data) {
            return data.map(item => {
                const formattedItem = {
                    code: item.code,
                    name: item.name,
                };
                // 只有在存在子节点时才添加children属性
                if (item.children && item.children.length > 0) {
                    formattedItem.children = [];
                }
                return formattedItem;
            });
        },
        handleChange(value) {
            let checkedNode = this.$refs.Cascader.getCheckedNodes()[0];
            value.forEach((val, index) => {
                let label = checkedNode.pathLabels[index];
                console.log({name: label, code: val})
            })
        },
        expandChange(value) {
        },

三、完整代码

①:Vue页面

<template>
    <!-- 添加或修改长者信息对话框 -->
    <el-dialog :title="title"
               v-loading="loading" :visible.sync="open"
               width="1000px" append-to-body :append-to-body="false"
               :modal-append-to-body="false" :close-on-click-modal="false">
        <el-form ref="form" :rules="rules" label-width="110px">
            <!-- 基础信息 -->
            <el-divider>基础信息</el-divider>

            <el-row :gutter="24">
                <el-col :span="8">
                    <el-form-item label="姓名" prop="realName">
                        <el-input v-model="form.realName" placeholder="请输入姓名"/>
                    </el-form-item>
                </el-col>
                <el-col :span="7">
                    <el-form-item label="性别" prop="gender">
                        <el-select v-model="form.gender" style="width: 150px" filterable placeholder="请选择性别">
                            <el-option v-for="item in gender_list" :label="item.label" :value="item.value"></el-option>
                        </el-select>
                    </el-form-item>
                </el-col>
                <el-col :span="8">
                    <el-form-item label="联系电话" prop="phone">
                        <el-input v-model="form.phone" placeholder="请输入联系电话"/>
                    </el-form-item>
                </el-col>
            </el-row>

            <el-row :gutter="24">
                <el-col :span="8">
                    <el-form-item label="身份证号" prop="identityNumber">
                        <el-input v-model="form.identityNumber" placeholder="请输入身份证号"/>
                    </el-form-item>
                </el-col>

                <el-col :span="7">
                    <el-form-item label="年龄" prop="age">
                        <el-input-number v-model="form.age" style="width: 150px" :min="1" :max="150"
                                         placeholder="请输入年龄"></el-input-number>
                    </el-form-item>
                </el-col>

                <el-col :span="8">
                    <el-form-item label="出生日期" prop="birthDate">
                        <el-date-picker style="width: 196px" v-model="form.birthDate" type="date"
                                        value-format="yyyy-MM-dd"
                                        :append-to-body="false" :editable="false" :clearable="false"
                                        placeholder="选择日期"
                        ></el-date-picker>
                    </el-form-item>
                </el-col>

            </el-row>

            <el-row :gutter="24">
                <el-col :span="23">
                    <el-form-item label="家庭住址" prop="valueData">
                        <el-cascader
                            v-model="valueData"
                            :props="cascaderProps"
                            :options="options"
                            placeholder="请选择家庭住址"
                            :disabled="false"
                            :clearable="true"
                            expandTrigger="hover"
                            separator='/'
                            ref="Cascader"
                            style="width: 100%;"
                            @change="handleChange"
                            @expand-change="expandChange"
                        ></el-cascader>
                    </el-form-item>
                </el-col>
            </el-row>
            <el-row :gutter="24">
                <el-col :span="23">
                    <el-form-item label="详细地址" prop="addr">
                        <el-input type="textarea" maxlength="1000" show-word-limit :autosize="{ minRows: 1, maxRows: 3}"
                                  v-model="form.addr"
                                  placeholder="请输入详细地址"
                        ></el-input>
                    </el-form-item>
                </el-col>
            </el-row>


            <!-- 急救信息 -->
            <el-divider>急救信息</el-divider>

            <el-row :gutter="24">
                <el-col :span="7">
                    <el-form-item label="紧急联系人姓名" prop="emergencyName">
                        <el-input v-model="form.emergencyName" placeholder="请输入姓名"/>
                    </el-form-item>
                </el-col>

                <el-col :span="8">
                    <el-form-item label="紧急联系人电话" prop="emergencyPhone">
                        <el-input v-model="form.emergencyPhone" placeholder="请输入联系电话"/>
                    </el-form-item>
                </el-col>
                <el-col :span="8">
                    <el-form-item label="居委会电话" prop="communityPhone">
                        <el-input v-model="form.communityPhone" placeholder="请输入居委会电话"/>
                    </el-form-item>
                </el-col>
            </el-row>

            <el-row :gutter="24">

            </el-row>

        </el-form>
        <div slot="footer" class="dialog-footer">
            <el-button type="primary" @click="submitForm">确 定</el-button>
            <el-button @click="cancel">取 消</el-button>
        </div>
    </el-dialog>
</template>

<script>
import {validIdentityNumber} from "@/utils/utils";

import provinces from 'china-division/dist/provinces.json';
import cities from 'china-division/dist/cities.json';
import areas from 'china-division/dist/areas.json';
import streets from 'china-division/dist/streets.json';
import villages from 'china-division/dist/villages.json';

export default {
    name: "AddElder",
    data() {
        return {
            // 弹出层标题
            title: "",
            // 是否显示弹出层
            open: false,
            loading: false, // 弹窗 加载loading
            // 表单参数
            form: {},
            gender_list: [{label: '男性', value: 'M'}, {label: '女性', value: 'F'}],

            valueData: [],
            cascaderProps: {
                value: 'code',
                label: 'name',
                children: 'children',
                emitPath: true,
                lazy: true,
                lazyLoad: this.lazyLoad,
                checkStrictly: true,
            },
            options: [],

            // 表单校验
            rules: {
                realName: [
                    {required: true, message: "姓名不能为空", trigger: "blur"}
                ],
                gender: [
                    {required: true, message: "性别不能为空", trigger: "blur"}
                ],
                phone: [
                    {required: true, message: "联系电话不能为空", trigger: "blur"}
                ],
                identityNumber: [{validator: this.validID, trigger: 'blur'}],
                age: [
                    {required: true, message: "年龄不能为空", trigger: "blur"}
                ],
            }
        }
    },
    mounted() {
        // 加载初始数据(省级)
        this.loadProvinces();
    },
    methods: {
        /** 新增按钮操作 */
        handleAdd() {
            this.reset();
            this.open = true;
            this.title = "新增长者信息";
        },
        // 取消按钮
        cancel() {
            this.open = false;
            this.reset();
        },
        // 表单重置
        reset() {
            this.form = {
                realName: null, // 姓名
                gender: 'M', // 性别
                phone: null, // 联系电话
                age: null, // 年龄
                identityNumber: null, // 身份证号
                birthDate: null, // 出生日期
                addr: null, // 详细地址
                emergencyName: null, // 紧急联系人姓名
                emergencyPhone: null, // 紧急联系人电话
                communityPhone: null, // 居委会电话
                deptCheckStrictly: true,
                remark: undefined,
            };
        },
        // 身份证验证
        async validID(rule, value, callback) {
            // 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X
            let reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
            if (reg.test(value)) {
                let res = await validIdentityNumber(value, value.length);
                if (res) {
                    if (!this.form.age || this.form.age === 1) this.form.age = res.age
                    if (!this.form.birthDate) this.form.birthDate = res.birthDate
                    if (!this.form.gender) this.form.gender = res.gender
                }
                callback()
            } else {
                callback(new Error('身份证号码不正确'))
            }
        },


        loadProvinces() {
            const provincesData = provinces.map(province => ({
                code: province.code,
                name: province.name,
            }));
            this.options = provincesData;

        },
        lazyLoad(node, resolve) {
            const {level, value} = node;
            console.log(level, value)
            let children = [];

            switch (level) {
                case 1:
                    children = this.formatData(cities.filter(city => city.provinceCode === value));
                    break;
                case 2:
                    children = this.formatData(areas.filter(area => area.cityCode === value));
                    break;
                case 3:
                    children = this.formatData(streets.filter(street => street.areaCode === value));
                    break;
                case 4:
                    children = this.formatData(villages.filter(street => street.streetCode === value));
                    break;
            }
            if (children && children.length > 0) {
                resolve(children);
            } else {
                resolve()
            }
        },
        formatData(data) {
            return data.map(item => {
                const formattedItem = {
                    code: item.code,
                    name: item.name,
                };
                // 只有在存在子节点时才添加children属性
                if (item.children && item.children.length > 0) {
                    formattedItem.children = [];
                }
                return formattedItem;
            });
        },
        handleChange(value) {
            let checkedNode = this.$refs.Cascader.getCheckedNodes()[0];
            value.forEach((val, index) => {
                let label = checkedNode.pathLabels[index];
                console.log({name: label, code: val})
            })
        },
        expandChange(value) {
        },

        /** 提交按钮 */
        submitForm: function () {
            // this.$refs["form"].validate(valid => {
            //     if (valid) {
            //         if (this.form.roleId != undefined) {
            //             this.form.menuIds = this.getMenuAllCheckedKeys();
            //             updateRole(this.form).then(response => {
            //                 this.$modal.msgSuccess("修改成功");
            //                 this.open = false;
            //                 this.getList();
            //             });
            //         } else {
            //             this.form.menuIds = this.getMenuAllCheckedKeys();
            //             addRole(this.form).then(response => {
            //                 this.$modal.msgSuccess("新增成功");
            //                 this.open = false;
            //                 this.getList();
            //             });
            //         }
            //     }
            // });
        },
    }
}
</script>

<style scoped lang="scss">

</style>

②:Js代码(util.js)

import {saveAs} from 'file-saver';
import axios from 'axios';
// import areas from 'china-division/dist/areas.json';
// import streets from 'china-division/dist/streets.json';
// import villages from 'china-division/dist/villages.json';
// console.log(areas)
// console.log(streets)
// console.log(villages)


/**
 * 根据身份证实现自动生成生日,性别,年龄
 * @param idEn
 * @param val
 */
export async function validIdentityNumber(idEn, val) {
    let sex = null;
    let birth = null;
    let myDate = new Date();
    let month = myDate.getMonth() + 1;
    let day = myDate.getDate();
    let age = 0;

    if (val === 18) {
        age = myDate.getFullYear() - idEn.substring(6, 10) - 1;
        sex = idEn.substring(16, 17);
        birth = idEn.substring(6, 10) + "-" + idEn.substring(10, 12) + "-" + idEn.substring(12, 14);
        if (idEn.substring(10, 12) < month || idEn.substring(10, 12) === month && idEn.substring(12, 14) <= day) age++;

    }
    if (val === 15) {
        age = myDate.getFullYear() - idEn.substring(6, 8) - 1901;
        sex = idEn.substring(13, 14);
        birth = "19" + idEn.substring(6, 8) + "-" + idEn.substring(8, 10) + "-" + idEn.substring(10, 12);
        if (idEn.substring(8, 10) < month || idEn.substring(8, 10) === month && idEn.substring(10, 12) <= day) age++;
    }
    //性别  ==> 1:男       0:女
    return {
        gender: sex % 2 === 0 ? 'F' : 'M',
        age: age,
        birthDate: birth
    }
}


// 获取上海所有的区、街道、社区
let shanghai_code = '31';
export let shanghai_area, shanghai_street, shanghai_village = []
// 上海所有区
// export const shanghai_area = get_china_division_formatData(areas.filter(area => area.provinceCode === shanghai_code));
 fetchShanghaiArea('/json/shanghai_area.json').then(res => {
    shanghai_area = res;
    // console.log('shanghai_area', shanghai_area)
})
//  上海所有街道
// shanghai_street = get_china_division_formatData(streets.filter(street => street.provinceCode === shanghai_code));
fetchShanghaiArea('/json/shanghai_street.json').then(res => {
    shanghai_street = res;
    // console.log('shanghai_street', shanghai_street)
})

//  上海所有社区
// shanghai_village = get_china_division_formatData(villages.filter(village => village.provinceCode === shanghai_code));
fetchShanghaiArea('/json/shanghai_village.json').then(res => {
    shanghai_village = res;
    // console.log('shanghai_village', shanghai_village)
})

// console.log('shanghai_area', shanghai_area)
// console.log('shanghai_street', shanghai_street)
// console.log('shanghai_village', shanghai_village)
export function get_china_division_formatData(flag, data) {
    return data.map(item => {
        return {
            code: item.code,
            name: item.name,
            provinceCode: item.provinceCode,
            cityCode: item.cityCode,
            areaCode: item.areaCode,
            streetCode: item.streetCode,
            leaf: flag,   // 设置叶子节点,确保没有右箭头
        };
    });
}


/**
 * 自动移除children字段
 * @param data
 * @returns {*}
 */
export function auto_remove_children_formatData(data) {
    return data.map(item => {
        const formattedItem = {
            code: item.code,
            name: item.name,
        };
        if (item.children && item.children.length > 0) {
            formattedItem.children = item.children;
        }
        return formattedItem;
    });
}

export function get_shanghai_division_by_levelAndCode(level, code) {
    let children = [];
    console.log('level', level, 'code', code)
    switch (level) {
        case 1:
            children = get_china_division_formatData(false, shanghai_street.filter(street => street.areaCode === code));
            break;
        case 2:
            children = get_china_division_formatData(true, shanghai_village.filter(village => village.streetCode === code));
            break;
    }
    return children;
}

// 执行保存 案例
// saveToFile(shanghai_street, 'shanghai_street.json')
/**
 * 函数用于保存数据到JSON文件
 * @param data
 * @param filename
 */
function saveToFile(data, filename) {
    const json = JSON.stringify(data);
    const blob = new Blob([json], {type: 'application/json'});
    saveAs(blob, filename);
}


/**
 * 从本地json文件中读取地区数据
 * @param path
 * @returns {Promise<any|null>}
 */
export async function fetchShanghaiArea(path) {
    try {
        const response = await axios.get(path);
        return response.data;
    } catch (error) {
        console.error('获取文件时出错:', error);
        return null;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七@归七

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值