使用了 Element UI 中的 el-cascader 组件,并对其进行了进一步封装和定制
创建组件index.vue (src/components/addressCascader/index.vue)
vue
<template>
<div>
<el-cascader
v-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.cascaderList
this.$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].level
this.$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 data
if (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.cascaderList
this.$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语句引入组件注册并使用
vue
<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,并在项目中引入它们。