开开心心工作,兢兢业业生活
一、实现省市区级联选择(插件)
1. 需求:实现一个省市区的级联选择器,点击一级,动态加载下一级
那好,我们找个轮子
2. 他山之石(找个轮子)
Element UI 中国省市区级联数据
安装:
npm install element-china-area-data -S
使用:
<template> <div id="app"> <el-cascader size="large" :options="options" v-model="selectedOptions" @change="handleChange"> </el-cascader> </div></template> <script> import { regionData } from 'element-china-area-data' export default { data () { return { options: regionData, selectedOptions: [] } }, methods: { handleChange (value) { console.log(value) } } }</script>
预览:
回复:
领导: 不行,多余的包会影响加载速度,我们有自己的接口
二、实现行政区三级选择 – 自己封装
1. 需求:
请求接口,获取第一级内容(省份),点击省份项,请求数据,获取第二级内容(城市)并动态加载出来,点击城市,请求数据,动态加载第三级内容(区域)
2. 组件选择
Element UI 的 Demo:
<el-cascader :props="props"></el-cascader><script> let id = 0; export default { data() { return { props: { lazy: true, lazyLoad (node, resolve) { const { level } = node; setTimeout(() => { const nodes = Array.from({ length: level + 1 }) .map(item => ({ value: ++id, label: `选项${id}`, leaf: level >= 2 })); // 通过调用resolve将子节点数据返回,通知组件数据加载完成 resolve(nodes); }, 1000); } } }; } };</script>
核心:
// 理解 level 的目的和意义const nodes = Array.from({ length: level + 1 })
3. 话不多说(直接组件封装)
组件:
<template> <div class="cascaderArea"> <el-cascader :props="props" v-model="selectedOptions" placeholder="请选择行政区域" @change="handleChange" style="width: 270px" ></el-cascader> </div></template><script>import { areaOption } from '@/assets/api'export default { name: 'cascaderArea', data() { return { selectedOptions: [], props: { lazy: true, lazyLoad: (node, resolve) => { const { level } = node // node 节点数据 const nodes = [] // 动态节点 let type = level == 0 ? "0" : node.value // 0 代表第一次请求 this.provinceFn(type) .then((res) => { res.list.map((item) => { let area = { value: item.id, label: item.areaName, leaf: node.level >= 2, }; nodes.push(area) }); resolve(nodes) // 回调 }) .catch((error) => { console.log(error) }) }, } } }, methods: { provinceFn(id) { // 获取省市区街道 return areaOption(id) }, handleChange(value) { // 选择的行政区 this.$emit('getSelectedOptions', value) } }}</script><style lang="scss" scoped></style>
父组件:
<template><CascaderArea @getSelectedOptions='getSelectedOptions' /></template><script>import CascaderArea from '@/components/cascaderArea.vue'...components: { CascaderArea },methods: { getSelectedOptions(val) { this.selectedOptions = val } }</script>
4. 预览:
5. 反思:
这个级联选择器不仅仅可以用在省市区的级联选择上,更可以面对庞大数据,做一个多层级选择菜单,实现数据的分级渲染
三、实现行政区三级自由选择
1. 存在的问题:
- 上面这个级联选择器要求必须选定第三级,不能直接选择一级 / 二级
- 如果第三级无数据,会导致无法选择
2. 思路:
- 样式: 采用 select 来实现,进行下拉框一个个选择
- 动态显示: 监听上一个下拉框是否有内容,决定要不要显示下一个 select
- 动态加载: 获取上一个下拉框内容作为参数,请求下一个下拉框的数据,如果返回数据为空,也不显示该 select(解决第三级无数据导致无法选择的问题)
- 非空校验: 只校验第一个下拉框内容是否为空,只要第一个输入框不为空可以直接提交
- 回显: 需要后端返回行政区全名,传入第一个下拉框,获取焦点时重新选择
3. 代码实现:
HTML:
<el-form-item label="行政区域地址" prop="province" class="wholeLine"> <el-select v-model="lineData.province" placeholder="请选择省份" @change="provinceSelect" > <el-option v-for="item in provinceOptions" :label="item.areaName" :key="item.id" :value="item.id" ></el-option> </el-select> <el-select v-show="this.lineData.province && this.cityOptions.length != 0" v-model="lineData.regionCity" placeholder="请选择城市" @change="citySelect" > <el-option v-for="item in cityOptions" :label="item.areaName" :key="item.id" :value="item.id" ></el-option> </el-select> <el-select v-show="this.lineData.regionCity && this.countyOptions.length != 0" v-model="lineData.regionCounty" placeholder="请选择县/区" @change="countySelect" > <el-option v-for="item in countyOptions" :label="item.areaName" :key="item.id" :value="item.id" ></el-option> </el-select> </el-form-item>
JS:
provinceSelect(val) { // 省份 下拉框值改变时回调 this.provinceFullName = this.getLabel(val, this.provinceOptions) if (this.lineData.regionCity) { // 千万要做一层判断,直接置空会导致 mode 绑定为 空 this.lineData.regionCity = '' } if (this.lineData.regionCounty) { this.lineData.regionCounty = '' } area(val) .then(res => { this.cityOptions = res.list }) }, citySelect(val) { // 城市 下拉框值改变时回调 this.cityFullName = this.getLabel(val, this.cityOptions) if (this.lineData.regionCounty) { // 千万要做一层判断,直接置空会导致 mode 绑定为 空 this.lineData.regionCounty = '' } area(val) .then(res => { this.countyOptions = res.list }) }, countySelect(val) { // 区/县 下拉框值改变时回调 this.countyFullName = this.getLabel(val, this.countyOptions) },
4. 预览:
5. 思考:
如果有更好的解决方案可以留言,感谢批评指正
- 自由选择无提示: 用户能够自由选择 一 / 二 / 三级,这点提示性不强
- 回显: 动态加载导致不能回显是通病,需要后端返回一个字段专门用于回显
- 输入框样式: 输入框的样式不够优雅,可以尝试使用
el-tree
开开心心工作,认认真真生活~