中國省市區街道四級聯動地區選擇元件

劉文磊發表於2018-03-28

中國省市區街道四級聯動地區選擇元件

效果圖

中國省市區街道四級聯動地區選擇元件

中國省市區街道四級聯動地區選擇元件

主要程式碼

<template>
  <div class="lw-area-select" id="lwAreaSelect">
    <div class="lw-virtual-input" @click="openDropDown">{{value}}</div>
    <div v-show="dropDown.open" class="lw-area-dropdown">
      <div class="lw-area-tab"><!--
     --><span
         v-if="innerLevel >= 1"
         :style="`width: calc(100%/${innerLevel});`"
         :class="{active: currentTab === 'province'}"
         @click="handleTabChange('province')">
         省份
        </span><!--
     --><span
         v-if="innerLevel >= 2"
         :style="`width: calc(100%/${innerLevel});`"
         :class="{active: currentTab === 'city'}"
         @click="handleTabChange('city')">
         市區
        </span><!--
     --><span
         v-if="innerLevel >= 3"
         :style="`width: calc(100%/${innerLevel});`"
         :class="{active: currentTab === 'district'}"
         @click="handleTabChange('district')">
         縣區
        </span><!--
     --><span
         v-if="innerLevel >= 4"
         :style="`width: calc(100%/${innerLevel});`"
         :class="{active: currentTab === 'street'}"
         @click="handleTabChange('street')">
         街道
        </span><!--
   --></div>
     <div class="lw-area-content">
       <dl v-show="currentTab === 'province'" class="fn-clear fn-clear-province" v-for="(value, key) in areas['86']">
         <dt>{{key}}</dt>
         <dd>
           <a :class="{selected: province.key === ky}" v-for="(val, ky) in value" :title="val" :data-id="ky" href="javascript:;" @click="handleAreaSelect(ky, val)">{{val}}</a>
         </dd>
       </dl>
       <dl v-show="currentTab === 'city'" class="fn-clear fn-clear-city" >
         <dd v-for="(value, key) in areas[province.key]">
           <a :class="{selected: city.key === key}" :title="value" :data-id="key" href="javascript:;" @click="handleAreaSelect(key, value)">{{value}}</a>
         </dd>
       </dl>

       <dl v-show="currentTab === 'district'" class="fn-clear fn-clear-district" >
         <dd v-for="(value, key) in areas[city.key]">
           <a :class="{selected: district.key === key}" :title="value" :data-id="key" href="javascript:;" @click="handleAreaSelect(key, value)">{{value}}</a>
         </dd>
       </dl>

       <dl v-show="currentTab === 'street'" class="fn-clear fn-clear-street" >
         <dd v-for="(value, key) in areas[district.key]">
           <a :class="{selected: street.key === key}" :title="value" :data-id="key" href="javascript:;" @click="handleAreaSelect(key, value)">{{value}}</a>
         </dd>
       </dl>
     </div>

    </div>
  </div>
</template>

<script>
import data from './data.js'
import $ from 'jquery'
export default {
  name: 'AreaSelect',
  model: {
    props: 'value',
    event: 'change'
  },
  props: {
    value: {
      type: String,
      default: function() {
        return ''
      }
    },
    level: {
      type: String,
      default: function() {
        return 'street'
      }
    }
  },
  data() {
    return {
      areas: data,
      innerLevel: 4,
      dropDown: {
        open: false
      },
      currentTab: 'province',
      province: {
        key: '',
        value: ''
      },
      city: {
        key: '',
        value: ''
      },
      district: {
        key: '',
        value: ''
      },
      street: {
        key: '',
        value: ''
      }
    }
  },
  computed: {
    selectedArea() {
      let [key, value] = ['', '']
      if (this.province.key !== '') {
        key += this.province.key
        value += this.province.value
      }
      console.log('province:', this.province.value)
      if (this.city.key !== '') {
        key += '/' + this.city.key
        value += '/' + this.city.value
      }
      console.log('city:', this.city.value)
      if (this.district.key !== '') {
        key += '/' + this.district.key
        value += '/' + this.district.value
      }
      console.log('district:', this.district.value)
      if (this.street.key !== '') {
        key += '/' + this.street.key
        value += '/' + this.street.value
      }
      console.log('street:', this.street.value)
      console.log('------------------------------------------------------')
      return { key, value }
    }
  },
  watch: {
    'selectedArea.value'(newVal, oldVal) {
      this.$emit('change', newVal)
    }
  },
  created() {
    this.innerLevel = this.calcInnerLevel(this.level)
    this.addBlurEvent()
  },
  methods: {
    openDropDown() {
      this.dropDown.open = true
    },
    calcInnerLevel(level) {
      if (level === 'province') return 1
      if (level === 'city') return 2
      if (level === 'district') return 3
      return 4
    },
    addBlurEvent() {
      $(document).click('click', (event) => {
        if (this.dropDown.open) {
          if ($(event.target).closest('#lwAreaSelect')[0] !== $('#lwAreaSelect')[0]) {
            this.$emit('blur')
            this.dropDown.open = false
          }
        }
      })
    },
    handleAreaSelect(key, value) {
      const targetElement = $(`[data-id=${key}]`)
      this.clearNextLevelData()
      if (targetElement.hasClass('selected')) {
        targetElement.removeClass('selected')
      } else {
        this.outputNextLevelData(key, value)
      }
    },
    outputNextLevelData(key, value) {
      this[this.currentTab] = { key, value }// 儲存當前級別的地區資訊即可遍歷生成下一級別的資料
      if (this.currentTab !== this.level) {
        if (this.currentTab === 'province') {
          this.currentTab = 'city'
        } else if (this.currentTab === 'city') {
          this.currentTab = 'district'
        } else if (this.currentTab === 'district') {
          this.currentTab = 'street'
        }
      } else {
        this.$emit('blur')
        this.dropDown.open = false
      }
    },
    handleTabChange(tabName) {
      this.currentTab = tabName
    },
    clearNextLevelData() {
      if (this.currentTab === 'province') {
        this.province = { key: '', value: '' }
        this.city = { key: '', value: '' }
        this.district = { key: '', value: '' }
        this.street = { key: '', value: '' }
      } else if (this.currentTab === 'city') {
        this.city = { key: '', value: '' }
        this.district = { key: '', value: '' }
        this.street = { key: '', value: '' }
      } else {
        this.district = { key: '', value: '' }
        this.street = { key: '', value: '' }
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.lw-area-select {
  position: relative;
  .lw-virtual-input {
    height: 40px;
    border: 1px solid #dcdfe6;
    border-radius: 4px;
  }
  .lw-area-dropdown {
    position: absolute;
    z-index: 2005;
    width: 100%;
    background-color: #fff;
    border: 1px solid #dcdfe6;
    font-size: 12px;
    .lw-area-tab {
      height: 40px;
      >span {
        display: inline-block;
        text-align: center;
        font-size: 14px;
        border-right: 1px solid #ccc;
        border-bottom: 1px solid #ccc;
        background-color: #f0f0f0;
        &:last-child {
          border-right: none;
        }
        &.active {
          background-color: #fff;
          border-bottom-color: #fff;
        }
      }
    }
    .lw-area-content {
      padding: 16px;
      .fn-clear {
        &.fn-clear-city,
        &.fn-clear-district,
        &.fn-clear-street {
          >dd {
            margin-left: 0;
          }
        }
        >dt {
          display: inline-block;
          width: 35px;
          position: absolute;
        }
        >dd {
          display: inline-block;
          >a {
            padding: 0 10px;
            height: 24px;
            display: inline-block;
            line-height: 24px;
            border-radius: 2px;
            &.selected {
              background-color: #f00;
              border-radius: 2px;
              color: #fff;
            }
          }
        }
      }
    }
  }
}
</style>

複製程式碼

相關文章