Vue城市多选组件

效果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": 
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值