基于vue2+element实现省市搜索面板(模仿高德地图搜索面板)

9 篇文章 1 订阅
7 篇文章 0 订阅

最终效果:

 

 

 相关代码:areaSearch.vue

<template>
  <div class="area-search">
    <div class="city-chose" ref="cityChose">
      <el-input
        readonly
        v-model="curCity"
        @click.native.stop="iptClick"
        class="cur-ipt"
      >
        <span slot="suffix" class="el-icon-arrow-down ipt-fate-suffix"></span>
      </el-input>
      <div class="cityChose-panel" v-show="panelShow">
        <div class="cityChose-panel-top">
          当前城市:{{ curCity }}
          <em
            class="fd-fr el-icon-close panel-close"
            @click="panelShow = false"
          ></em>
        </div>
        <div class="hotCity-div clearfix">
          <div
            class="fd-fl hotCity-item"
            v-for="item in hotCity"
            :key="item.name_en"
            @click="cityClick(item)"
          >
            {{ item.name }}
          </div>
        </div>
        <div
          class="panel-tackle clearfix"
          style="margin: 5px 0; padding-right: 10px"
        >
          <div class="panel-toggle clearfix fd-fl">
            <div
              :class="[
                'fd-fl',
                'panel-toggle-item',
                { 'active-item': activeItem === 1 },
              ]"
              @click="toggleClick(1)"
            >
              按省份
            </div>
            <div
              :class="[
                'fd-fl',
                'panel-toggle-item',
                { 'active-item': activeItem === 2 },
              ]"
              @click="toggleClick(2)"
            >
              按城市
            </div>
          </div>
          <el-autocomplete
            class="fd-fr"
            style="width: 150px"
            prefix-icon="el-icon-search"
            placeholder="请输入城市"
            :fetch-suggestions="querySearch"
            :trigger-on-focus="false"
            v-model="manualSearch"
            value-key="name"
            @select="autoSelect"
          ></el-autocomplete>
        </div>
        <div class="anchor-out clearfix">
          <div
            :class="['anchor', 'fd-fl', { activeAnchor: curAnchor === item }]"
            v-for="item in anchorArr"
            :key="item"
            @click="anchorClick(item)"
          >
            {{ item }}
          </div>
        </div>
        <!-- 按省份 -->
        <div class="city-list" v-if="activeItem === 1">
          <div v-for="(item, key) in provinceByLetter" :key="key" :id="key">
            <div v-for="(item1, key1) in item" class="clearfix" :key="key1">
              <div
                v-for="(item2, key2) in item1"
                :key="key2"
                class="clearfix city-circle"
              >
                <div class="fd-fl city-bold">{{ key2 }}:</div>
                <div class="fd-fl city-content clearfix">
                  <div
                    v-for="item3 in item2"
                    :key="item3.adcode"
                    class="fd-fl cityName"
                    @click="cityClick(item3)"
                  >
                    {{ item3.name }}
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <!-- 按城市 -->
        <div class="city-list" v-if="activeItem === 2">
          <div
            v-for="(item, key) in cityByLetter"
            :key="key"
            :id="key"
            class="clearfix city-circle"
          >
            <div class="fd-fl city-bold">{{ key }}:</div>
            <div class="fd-fl city-content clearfix">
              <div
                v-for="item2 in item"
                :key="item2.adcode"
                class="fd-fl cityName"
                @click="cityClick(item2)"
              >
                {{ item2.name }}
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      hotCity: [], // 热门城市列表
      activeItem: 1, // 1:按省份 2:按城市
      cityByLetter: null, // 按城市数据
      provinceByLetter: null, // 按省份数据
      anchorArr: [],
      curCity: '北京',
      curAnchor: '', // 当前锚点
      panelShow: false,
      allCitys: [], // 所有城市数据
      manualSearch: '' // 手动搜索的城市名称
    }
  },
  created () {
    this.getAllData()
  },
  mounted () {
    this.$nextTick(() => {
      document.addEventListener('click', this.docClick)
    })
  },
  beforeDestroy () {
    document.removeEventListener('click', this.docClick)
  },
  methods: {
    getAllData () {
      this.$axios.get('static/json/geoinfo-all.json').then((res) => {
        // console.log(res.data, 'ge0-all')
        this.hotCity = res.data.data.cityData.hotCitys
        this.cityByLetter = res.data.data.cityByLetter
        this.provinceByLetter = res.data.data.provinceByLetter
        this.getAllCitys(res.data.data.cityData.provinces)
        this.toggleClick(1)
      })
    },
    /**
     * 获取所有城市
     * @param {} data
     */
    getAllCitys (data) {
      this.allCitys = []
      for (const key in data) {
        if (data[key].cities.length === 0) {
          this.allCitys.push({
            name: data[key].name,
            adcode: data[key].adcode,
            x: data[key].x,
            y: data[key].y
          })
        } else {
          data[key].cities.forEach((city) => {
            this.allCitys.push({
              name: city.name,
              adcode: city.adcode,
              x: city.x,
              y: city.y
            })
          })
        }
      }
      //   console.log(this.allCitys, 'all-city')
    },
    /**
     *
     * @param {*} num 1按省份 2按城市
     */
    toggleClick (num) {
      this.activeItem = num
      this.curAnchor = ''
      if (num === 1) {
        this.anchorArr = Object.keys(this.provinceByLetter)
      } else {
        this.anchorArr = Object.keys(this.cityByLetter)
      }
    },
    /**
     * 字母锚点 点击
     * @param {} val
     */
    anchorClick (val) {
      this.curAnchor = val
      document.getElementById(val).scrollIntoView({ behavior: 'smooth' })
    },
    iptClick () {
      this.panelShow = !this.panelShow
    },
    /**
     * document 点击事件
     * @param {*} e
     */
    docClick (e) {
      if (!this.$refs.cityChose.contains(e.target)) {
        this.panelShow = false
      }
    },
    querySearch (queryString, cb) {
      var allCitys = this.allCitys
      var results = queryString
        ? allCitys.filter((city) => {
          return (
            city.name.toLowerCase().indexOf(queryString.toLowerCase()) === 0
          )
        })
        : allCitys
      // 调用 callback 返回建议列表的数据
      cb(results)
    },
    /**
     * 手动搜索选定
     * @param {*} item
     */
    autoSelect (item) {
      this.curCity = item.name
      this.$emit('city', item)
      this.panelShow = false
    },
    /**
     * 城市点击
     * @param {*} item
     */
    cityClick (item) {
      if (item.name === '全国') {
        this.curCity = '全国'
        this.$emit('city', item)
        this.panelShow = false
        return
      }
      const len = this.allCitys.length
      for (let i = 0; i < len; i++) {
        if (item.adcode === this.allCitys[i].adcode) {
          this.curCity = this.allCitys[i].name
          this.$emit('city', this.allCitys[i])
          this.panelShow = false
          break
        }
      }
    }
  }
}
</script>
<style scoped lang="scss">
$border-corlor: rgba(121, 121, 121, 1);
$hoverColor: #33ccff;
.area-search {
  position: relative;
}
.city-chose {
  position: relative;
  .cityChose-panel {
    position: absolute;
    right: 0;
    width: 410px;
    height: 500px;
    border: 1px solid $border-corlor;
    margin-top: 10px;
    background-color: rgba(0, 0, 0, 0.537254901960784);
    display: flex;
    flex-direction: column;
  }
}
.hotCity-item {
  color: $hoverColor;
  margin: 2px 6px;
  cursor: pointer;
  &:hover {
    text-decoration: underline;
  }
}
.panel-toggle-item {
  color: rgba(204, 204, 204, 0.847058823529412);
  font-weight: bold;
  font-size: 15px;
  margin: 4px 6px;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  &.active-item {
    color: $hoverColor;
    border-color: $hoverColor;
  }
}
.panel-tackle {
  /deep/.el-input__inner {
    height: 24px;
  }
  /deep/.el-input {
    .el-input__prefix {
      top: -8px;
    }
  }
}
.anchor {
  background-color: rgba(204, 204, 204, 1);
  color: #666;
  margin: 2px 6px;
  width: 18px;
  text-align: center;
  cursor: pointer;
  &:hover {
    background-color: $hoverColor;
    color: #fff;
  }
  &.activeAnchor {
    background-color: $hoverColor;
    color: #fff;
  }
}
.city-list {
  flex: 1;
  overflow: auto;
  color: rgba(255, 255, 255, 0.847058823529412);
}
.city-circle {
  display: flex;
  padding: 6px;
  .city-bold {
    font-weight: 700;
  }
  .city-content {
    flex: 1;
  }
  .cityName {
    margin: 0 4px;
    cursor: pointer;
    line-height: 22px;
    &:hover {
      color: $hoverColor;
    }
  }
}
.cityChose-panel-top {
  font-weight: 700;
  font-style: normal;
  font-size: 16px;
  color: #cccccc;
  margin: 6px 6px 8px 6px;
  border-bottom: 1px solid $border-corlor;
  padding-bottom: 8px;
}
.panel-close {
  cursor: pointer;
  &:hover {
    opacity: 0.8;
  }
}
.ipt-fate-suffix {
  position: relative;
  top: 5px;
}
.cur-ipt {
  /deep/ input {
    background: transparent;
    color: #fff;
    border-color: $border-corlor;
    cursor: pointer;
  }
}
.fd-fl {
    float: left;
}
.fd-fr {
    float: right;
}
.clearfix::after {
    content: ' ';
    height: 0;
    visibility: hidden;
    display: block;
    clear: both;
}
</style>

 注意事项:

            axios.get('static/json/geoinfo-all.json') 获取到的数据是高德地图搜索面板的后台数据,以上所有代码都是基于该数据结构编写。在高德地图首页打开开发者工具查看network即可看到该数据,即https://amap.com/service/cityList?version=20225815

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值