效果DEMO:
组件需求
项目工具需求:给多个城市配置信息,城市选择具体到市,将全国这一选项设置为level=0,省level=1,市level=2。展示只展示level=2的市。
项目UI库:elementUI
组件实现
组件代码
// selectCitys.vue
<template>
<div class="abk-select-city" @click.stop="showCitysHandler">
<el-input
@input="inputChangeHandler"
v-model="searchText"
class="abk-select-input"
:placeholder="placeholderText">
<i slot="suffix" v-if="!showCitys" class="el-input__icon el-icon-caret-bottom"></i>
<i slot="suffix" v-else @click.stop="hideCitysHandler" class="el-input__icon el-icon-caret-top"></i>
</el-input>
<div class="dropdown-box" v-show="showCitys">
<div class="city-tree-box" v-show="showTrees">
<el-tree
:data="cityInfos"
ref="selectCityTree"
show-checkbox
@check-change="treeChangeHandler"
node-key="value">
</el-tree>
</div>
<div class="city-search-box" v-show="!showTrees">
<el-checkbox-group v-model="checkCitiesList">
<el-checkbox class="checkbox-item" v-for="city in searchResultsList"
:label="city.regionId"
:key="city.regionId"
@change="value => searchItemHandler(city, value)">
<span v-if="city.level === 2">{
{getCityNameByRegionId(city.upRegionId)}}</span> <span>{
{city.name}}</span>
</el-checkbox>
</el-checkbox-group>
<!-- <ul>
<li v-for="item in searchResultsList" @click="searchItemHandler(item)">{
{item.name}}</li>
</ul> -->
</div>
</div>
</div>
</template>
<style lang="less" scoped>
.abk-select-city{
position: relative;
width:300px;
.el-icon-caret-bottom,.el-icon-caret-top{
margin-top:-4px;
color: #528ED5;
}
.dropdown-box{
position: absolute;
left: 0;
right:0;
top:40px;
padding: 12px 0;
background-color: #fff;
border: 1px solid #e4e7ed;
border-radius: 4px;
z-index: 10;
.checkbox-item{
display: block;
padding: 0px 12px;
}
.el-checkbox+.el-checkbox{
margin-left: 0;
}
}
.city-tree-box{
max-height: 350px;
overflow-y:auto;
}
.city-search-box{
max-height: 250px;
overflow-y:auto;
li{
padding: 5px 12px;
}
li:hover{
background: #f5f7fa;
}
}
}
</style>
<style lang="less">
/* 取消框架下拉右侧箭头 */
.abk-select-city .el-input__suffix-inner{
display: inline-block;
}
</style>
<script>
/**
* <select-city ref="selectCity" placeholder="请输入省市啊"></select-city>
*
* 获取所有选中节点 this.$refs.selectCity.getCheckedList()
*/
import _ from 'lodash'
import {cityLists} from "@/api/json_regions";
let cityMap = {}
export default {
props: ['placeholder', 'checkcitylist'],
data(){
return {
infos:[],
citys: [],
showTrees: true,
showCitys: false,
searchText: '',
checkCitiesList: [],
searchResultsList: [],
placeholderText: this.placeholder || '请添加地区',
data1:null,
}
},
model: {
prop: 'checkcitylist',
event: 'change'
},
mounted(){
this.treeChangeHandler()
},
watch:{
citys(n,o){
this.placeholderText='请添加地区'
},
},
computed: {
cityInfos(){
let infos = []
this.citys = cityLists
let province = this.citys.filter(o => {
cityMap[o.regionId] = o.label
return o.level === 1
});
province.map(p => {
p.children = [];
this.citys.map(o => {
if (o.level === 2) {
if (o.value.substr(0, 2) === p.value.substr(0, 2)) {
p.children.push(o)
}
}
})
})
infos = [
{
label: '全国',
value: '000000',
level: 0,
children: province
}
]
return infos
},
checkedTreeNodes(){
let list = this.$refs.selectCityTree.getCheckedNodes();
return list
}
},
methods: {
setChecked () {
this.$nextTick(() => {
// 设置默认选中
this.$refs.selectCityTree.setCheckedKeys(this.checkcitylist);
this.treeChangeHandler();
});
},
hideSelectCityHandler(){
this.hideCitysHandler()
this.showTrees = true
this.searchText = ''
},
getCheckedList(){
// console.log('this.checkedTreeNodes', this.checkedTreeNodes)
return this.checkedTreeNodes;
},
getCityNameByRegionId(id){
return cityMap[id]
},
showCitysHandler(){
this.showCitys = true
document.removeEventListener('click', this.hideSelectCityHandler)
document.addEventListener('click', this.hideSelectCityHandler, false)
},
hideCitysHandler(){
this.showCitys = false
this.$emit('blur')
document.removeEventListener('click', this.hideSelectCityHandler)
},
inputChangeHandler(){
let searchKey = this.searchText.toUpperCase()
let citys = this.citys;
if(searchKey == ""){
this.searchResultsList = []
}else {
this.searchResultsList = citys
.filter( o => {
return o.level === 1 || o.level === 2
})
.filter( o => {
o.shortSpell = o.shortSpell || ''
o.spell = o.spell || ''
o.fullName = o.fullName || ''
return o.shortSpell.toUpperCase().indexOf(searchKey) === 0
|| o.spell.toUpperCase().indexOf(searchKey) === 0
|| o.fullName.indexOf(searchKey) === 0
})
}
this.showTrees = this.searchResultsList.length === 0
},
searchItemHandler(city, value){
this.$refs.selectCityTree.setChecked(city.regionId, value, true);
},
treeChangeHandler(){
if (!this.checkcitylist) {
this.$emit('change', this.getCheckedList())
}
if(this.getCheckedList()[0] && this.getCheckedList()[0].value === '000000'){
this.placeholderText = '全国地区'
}else{
this.placeholderText = this.getCheckedList().filter(o => o.level === 2 || o.level === 0).map(o => o.label).join(',') || this.placeholder || '请添加地区'
}
}
}
}
</script>
组件的使用
// main.js
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css'
Vue.use(Antd)
/**
* 说明:setCheckedKeys接收的市城市code的数组:["1", "2"]
*/
// 引入
import SelectCity from '@/***/SelectCity';
// 组件名
components: {
SelectCity
},
// html导入
<select-city ref="cityChild" placeholder="请选择省市" @change="getCityArr" v-model="selectedCityLists"></select-city>
// method
getCityArr(data) {
console.log('data', data)
this.selectedCityLists = data
},
补充
// 城市JSON
export const cityLists = [
{
"value": "110000",
"label": "北京",
"level": 1
},
{
"value": "110100",
"label": "北京",
"pre": "京",
"level": 2
},
{
"value": "120000",
"label": "天津",
"level": 1
},
{
"value": "120100",
"label": "天津",
"pre": "津",
"level": 2
},
{
"value": "130000",
"label": "河北省",
"level": 1
},
{
"value": "130100",
"label": "石家庄",
"pre": "冀A",
"level": 2
},
{
"value": "130200",
"label": "唐山",
"pre": "冀B",
"level": 2
},
{
"value": "130300",
"label": "秦皇岛",
"pre": "冀C",
"level": 2
},
{
"value": "130400",
"label": "邯郸",
"pre": "冀D",
"level": 2
},
{
"value": "130500",
"label": "邢台",
"pre": "冀E",
"level": 2
},
{
"value": "130600",
"label": "保定",
"pre": "冀F",
"level": 2
},
{
"value": "130700",
"label": "张家口",
"pre": "冀G",
"level": 2
},
{
"value": "130800",
"label": "承德",
"pre": "冀H",
"level": 2
},
{
"value": "130900",
"label": "沧州",
"pre": "冀J",
"level": 2
},
{
"value": "131000",
"label": "廊坊",
"pre": "冀R",
"level": 2
},
{
"value": "131100",
"label": "衡水",
"pre": "冀T",
"level": 2
},
{
"value": "140000",
"label": "山西省",
"level": 1
},
{
"value": "140100",
"label": "太原",
"pre": "晋A",
"level": 2
},
{
"value": "140200",
"label": "大同",
"pre": "晋B",
"level": 2
},
{
"value": "140300",
"label": "阳泉",
"pre": "晋C",
"level": 2
},
{
"value": "140400",
"label": "长治",
"pre": "晋D",
"level": 2
},
{
"value": "140500",
"label": "晋城",
"pre": "晋E",
"level": 2
},
{
"value": "140600",
"label": "朔州",
"pre": "晋F",
"level": 2
},
{
"value": "140700",
"label": "晋中",
"pre": "晋G",
"level": 2
},
{
"value": "140800",
"label": "运城",
"pre": "晋M",
"level": 2
},
{
"value": "140900",
"label": "忻州",
"pre": "晋H",
"level": 2
},
{
"value": "141000",
"label": "临汾",
"pre": "晋L",
"level": 2
},
{
"value": "141100",
"label": "吕梁",
"pre": "晋J",
"level": 2
},
{
"value": "150000",
"label":