使用了 Element UI 中的 el-cascader 组件,并对其进行了进一步封装和定制
创建组件index.vue (src/components/addressCascader/index.vue)
<template><div><el-cascaderv-if="showca"size="large":props="props":options="cascaderOption":placeholder="placeholder || '选择省/市/区'"v-model="selectedOptions"@change="addressChange"ref="place":disabled="disabled":clearable="clearable":popper-class=" 'cascader-default'"></el-cascader></div>
</template><script>import { getDistrictAllSelect, getDistrictFilterSelect } from '@/api/district'export default {props: {selectedVal: {type: [Number, String],default: ''},disabled: {type: Boolean,default: false},checkStrictly: {type: Boolean,default: false},isNeedFilter: {type: Boolean,default: true},clearable: {type: Boolean,default: false},placeholder: String},data () {return {props: {value: 'id',label: 'name',checkStrictly: this.checkStrictly,expandTrigger: 'hover'},newDistictId: '',selectedOptions: [],showca: true,timeout: null,isChoose: false,chooseLevel: 0,cascaderOption: [],originData: [],cascaderList: []}},watch: {selectedVal: {handler (val) {if (val) {if(this.originData.length>0) {this.cascaderList = []this.findParent(Number(this.selectedVal))this.cascaderList.push(Number(this.selectedVal))this.selectedOptions = this.cascaderListthis.$nextTick(() => {let label = this.$refs.place.getCheckedNodes()? this.$refs.place.getCheckedNodes()[0].pathLabels? this.$refs.place.getCheckedNodes()[0].pathLabels.join(''): '': ''let level = this.$refs.place.getCheckedNodes()? this.$refs.place.getCheckedNodes()[0].level: ''this.$emit('getVal',this.selectedOptions[this.selectedOptions.length - 1],label,level)})}} else {this.clearVal()}},immediate: true}},mounted () {this.getDistrictAllSelect()},beforeDestroy () {},methods: {findParent (idx) {this.originData.forEach(item => {if (idx.toString() === item.id.toString()) {let pid = item['parentId']if (pid !== 0) {this.cascaderList.unshift(pid)this.findParent(pid)}}})},addressChange (arr) {if (arr.length > 1) {this.isChoose = true}if (arr.length == 1) {this.chooseLevel = 0} else if (arr.length == 2) {this.chooseLevel = 1} else if (arr.length == 3) {this.chooseLevel = 3}if (arr.length == 0) {this.$emit('getVal', '')return}console.log(this.$refs.place.getCheckedNodes()[0],'this.$refs.place.getCheckedNodes()[0]')let label = this.$refs.place.getCheckedNodes()[0].pathLabels? this.$refs.place.getCheckedNodes()[0].pathLabels.join(''): ''let level = this.$refs.place.getCheckedNodes()[0].levelthis.$emit('getVal', arr[arr.length - 1], label, level)if (arr.length > 2) {this.$refs.place.dropDownVisible = false}},clearVal () {if (this.$refs.place) {this.selectedOptions = []this.$refs.place.$refs.panel.checkedValue = []this.$refs.place.$refs.panel.activePath = []this.$refs.place.$refs.panel.syncActivePath()}},async getDistrictAllSelect () {let dataif (this.checkStrictly && this.isNeedFilter) {data = await getDistrictFilterSelect()this.originData = data || []this.cascaderOption = this.transTree(data)} else {if (sessionStorage.pvRegionData&&sessionStorage.pvRegionOriginData!='undefined') {this.originData = JSON.parse(sessionStorage.pvRegionOriginData)this.cascaderOption = JSON.parse(sessionStorage.pvRegionData)} else {data = await getDistrictAllSelect()this.originData = data || []sessionStorage.setItem('pvRegionOriginData', JSON.stringify(data))this.cascaderOption = this.transTree(data)sessionStorage.setItem('pvRegionData',JSON.stringify(this.cascaderOption))}}if (this.selectedVal) {this.cascaderList = []this.findParent(Number(this.selectedVal))this.cascaderList.push(Number(this.selectedVal))this.selectedOptions = this.cascaderListthis.$nextTick(() => {let label = this.$refs.place.getCheckedNodes()? this.$refs.place.getCheckedNodes()[0].pathLabels? this.$refs.place.getCheckedNodes()[0].pathLabels.join(''): '': ''let level = this.$refs.place.getCheckedNodes()? this.$refs.place.getCheckedNodes()[0].level: ''this.$emit('getVal',this.selectedOptions[this.selectedOptions.length - 1],label,level)})}},transTree (data) {let result = []let map = {}if (!Array.isArray(data)) {//验证data是不是数组类型return []}data.forEach(item => {//建立每个数组元素id和该对象的关系map[item.id] = item //这里可以理解为浅拷贝,共享引用})data.forEach(item => {let parent = map[item.parentId] //找到data中每一项item的爸爸if (parent) {//说明元素有爸爸,把元素放在爸爸的children下面;(parent.children || (parent.children = [])).push(item)} else {//说明元素没有爸爸,是根节点,把节点push到最终结果中result.push(item) //item是对象的引用}})return result //数组里的对象和data是共享的}}}
</script><style scoped lang="scss"></style>
页面引入
- 在需要使用addressCascader组件的地方,通过import语句引入组件注册并使用
<template><div><address-cascader:selectedVal="selectedValue"@getVal="(districtVal, districtLabel, districtLevel) =>setDistrictId(districtVal, districtLabel, info, districtLevel)":isNeedFilter="info.isNeedFilter":checkStrictly="info.checkStrictly"ref="addressCascader":disabled="info.disabled"></address-cascader></div>
</template>
<script>import addressCascader from "@/components/addressCascader/index";export default {components: {addressCascader},data() {return {info:{clearable: true,isNeedFilter:false,valueFormat:'yyyy-MM-dd',checkStrictly: false,pickerOptions:{}},dataSource: [],selectedValue: ''}},methods: {setDistrictId(val, label, info, districtLevel) {console.log("选中的值,文字,信息,级别", val, label, info, districtLevel);}}// ...}
</script>
确保你已经安装了Vue.js和Element UI,并在项目中引入它们。