27

公司pc端有一个地图选址及查看地图功能,这个是几个月前就开发完了,最近完善了一下,先上最终效果吧。
选择省市区填写详细地址进入点击确认坐标打开地图弹框
选择省市区填写详细地址进入点击确认坐标打开地图弹框
根据传入的地址查询到了地址可以查看更多地址,可以点击地图查看周边,点击确认,获取坐标
根据传入的地址查询到了地址可以查看更多地址,可以点击地图查看周边,点击确认,获取坐标。

这是查看地址
这是查看地址

好了,上实现代码。

<template>
  <el-dialog title="" 
    :close-on-click-modal="false" 
    :destroy-on-close="true" 
    :visible.sync="visibleVal" 
    :modal="modal" width="800px" 
    class="x-ui-modal map__dialog">

    <div id="container"></div>

    <div class="poi__list" ref="scrollWrap" v-if="lists.length">
      <div class="ul">
        <div class="address-item"
          :class="nearbyIndex === choiceIndex ? 'active' : ''"
          @click.stop="choiceAddress(nearbyIndex)" 
          v-for="(nearby, nearbyIndex) in lists" :key="nearbyIndex">
          <div class="icon"></div>
          <div class="text">
            <div class="name" :title="nearby.name">{{nearby.name | ellipsis}}</div>
            <div class="address" :title="nearby.address">{{nearby.address | ellipsis}}</div>
          </div>
        </div>
        <div v-show="bottomLoadingShow"><Loading /></div>
        <div v-show="bottomLineShow"><BottomLine :text="'已无更多数据,点击地图\n任意一处可以查看周边'"/></div>
        <div v-show="moreShow" @click="loadingMore"><BottomLine :text="'上拉或点我查看更多'" style="cursor: pointer;" /></div>
      </div>
    </div>

    <div 
      v-if="isEdit"
      class="city__name"
      :title="`您查询的${customerName ? '客户及地址' : '地址'}:${searchKwords}`">
      <el-input
        v-model="searchKwords"
        disabled />
    </div>

    <template v-if="isEdit">
      <div class="main__footer">
        <el-button
          @click="onCloseModal()"
          class="x-ui-btn add__cancel"
          size="medium">取消</el-button>
        <el-button
          @click="onSubmit()"
          class="x-ui-btn add__submit"
          type="primary"
          size="medium">确认</el-button>
      </div>
    </template>

    <template v-else>
      <div class="main__footer">
        <el-button
          @click="onCloseModal()"
          class="x-ui-btn add__cancel"
          size="medium">关闭</el-button>
      </div>
    </template>
  </el-dialog>
</template>

以上是dom,用的是element-ui的dialog。

进入弹框后,编辑加载需要用到的地图插件,AMap.Geocoder和AMap.PlaceSearch,因为一开始做这个是时候,单独使用了一种AMap.Geocoder,很多高德地图上能查到的地址都定位不到,于是查看了文档的常见问题,里面的描述就是:“高德地图的搜索是复合型搜索......位置搜索的研发中,可以先进行地址解析,再进行关键词搜索,以得到更优的结果。” 查看则直接根据外部传入的经纬度定位,初始化地图。当然我这里是在保证AMap和AMapUI都已经加载到的情况下再做的,否则就会报错,我用了比较笨的办法,就是定时器不断执行加载的代码,然后在这里一旦两个都有了,就停止定时器,比较笨的办法了。

进入弹框后,编辑加载需要用到的地图插件,查看则直接根据经纬度定位,初始化地图。

下面就是编辑坐标时的逻辑了

interval() {
      this.timer = setInterval(function() {
        this.awaitPlaceSearch();
      }.bind(this), 50)
    },

    awaitPlaceSearch() {
      if(this.placeSearch && this.geoCoder) {
        clearInterval(this.timer);
        this.isUseNearBy = false;
        this.placeSearch.search(this.handleCityName, (status, result) => {
          if (status === 'complete') {
            if(result.poiList.pois.length) {
              if(result.poiList.pois.length % this.pageSize !== 0) {
                this.isUseNearBy = true;
                this.bottomLineShow = true;
              } else {
                this.isUseNearBy = false;
                this.bottomLineShow = false;
              }
              const geos = result.poiList.pois[0].location;
              this.center = [geos.lng, geos.lat];
              this.getAreaInfo('location', (res) => {
                this.lists = result.poiList.pois//将查询到的地点赋值
                this._initScroll();
                this.getAddress(0);
                this.createdMap([this.ruleForm.long, this.ruleForm.lat]);
                this.addMarker();
              })
            } else {
              if(result.cityList && result.cityList.length > 1) {
                this.lists = [];
                this.onCloseModal();
                this.$message.info(`当前搜索地址在${result.cityList.length}个城市有若干结果,请明确后再搜索`);
              } else {
                this.lists = [];
                this.onCloseModal();
                this.$message.info('未能查询到该地址,请更换关键字查询');
              }
            }
          } else if(status === 'no_data') {
            this.$message.warning(`您输入的地址“${this.cityName}”,未查询到相关信息`);
            this.getAreaInfo('address', (res) => {
              this.lists = [
                {
                  location: {
                    lng: res.geocodes[0].location.lng,
                    lat: res.geocodes[0].location.lat,
                  },
                  name: res.geocodes[0].formattedAddress,
                  address: '',
                }
              ]
              this.center = [res.geocodes[0].location.lng, res.geocodes[0].location.lat]
              this._initScroll();
              this.getAddress(0);
              this.createdMap([this.ruleForm.long, this.ruleForm.lat]);
              this.addMarker();
              this.isUseNearBy = true;
              this.bottomLineShow = true;
            });
          } else {
            this.fixedPosition();//精准定位或IP地址定位
          }
        }) 
      }
    },

当然也是在保证this.placeSearch和this.geoCoder(即AMap.Geocoder和AMap.PlaceSearch)都加载到,同样也是上面说的笨办法。我是先用AMap.PlaceSearch.search方法,通过关键字查询传入的地址,如果查询到,则确定新的地图中心点经纬度,再通过AMap.Geocoder.getAddress方法传入新的地图中心点经纬度,解析出省市区信息,也可能关键字查询不明确(未明确省市区),比如只写了xx路,就有可能在全国多处都有结果,则会关闭弹框,提示明确后再查询,还可能关键字根本就查询不到,AMap.PlaceSearch.search返回no_data,则传入关键字使用AMap.Geocoder.getLocation方法,解析关键字所在城市,总之这里的逻辑就是AMap.Geocoder和AMap.PlaceSearch搭配使用。此处this.getAreaInfo方法是解析地址省市区的方法,设置了一个回调函数作为参数:

//依赖高德该接口获得省市区信息
    getAreaInfo(type, callback) {
      if(type === 'address') { // 在编辑的情况下通过地址名称查询
        this.geoCoder.getLocation(this.handleCityName, (status, result) => {
          if (status === 'complete' && result.geocodes.length) {
            this.ruleForm.regeocode.adcode = result.geocodes[0].adcode
            this.ruleForm.regeocode.province = result.geocodes[0].addressComponent.province
            this.ruleForm.regeocode.city = result.geocodes[0].addressComponent.city == '' ? result.geocodes[0].addressComponent.province : result.geocodes[0].addressComponent.city
            this.ruleForm.regeocode.district = result.geocodes[0].addressComponent.district;
            callback(result);
          } else if(status === 'no_data') {
            this.lists = [];
            this.onCloseModal();
            this.$message.info('未能查询到该地址,请更换关键字查询');
          } else {
            this.fixedPosition();//精准定位或IP地址定位
          }
        });
      } else if(type === 'location') { // 在查看的情况下通过经纬度查询
        this.geoCoder.getAddress(this.center, (status, result) => {
          if (status === 'complete' && result.regeocode && result.regeocode.addressComponent) {
            this.ruleForm.regeocode.adcode = result.regeocode.addressComponent.adcode
            this.ruleForm.regeocode.province = result.regeocode.addressComponent.province
            this.ruleForm.regeocode.city = result.regeocode.addressComponent.city == '' ? result.regeocode.addressComponent.province : result.regeocode.addressComponent.city
            this.ruleForm.regeocode.district = result.regeocode.addressComponent.district;
            callback(result);
          } else {
            this.fixedPosition();//精准定位或IP地址定位
          }
        });
      }
    },

以上在获取到地址时都会设置为一个地址列表,设置在地图左侧,供用户选择,滚动使用better-scroll,可以上拉加载进行分页,这里不展开说了。

通过以上步骤,大部分情况下都能查询到精确的关键字,一部分高德没有收录的企业信息,也能定位到所在街道乡镇省市区。此外还在点击地图的时候触发了AMap.PlaceSearch.searchNearBy方法查询鼠标点击处的周边,作为补充:

// 查看更多,此方法也给上拉加载使用
searchMore(e) {
      if(e) {
        this.isUseNearBy = true;
        this.placeSearch.opt.pageIndex = 1;
        this.center = [e.lnglat.getLng(), e.lnglat.getLat()];
      } else {
        this.placeSearch.opt.pageIndex += 1;
      }
      this.geoCoder.getAddress(this.center, (status, result) => {
        if (status === 'complete' && result.info === 'OK') {
          let addressComponent = result.regeocode.addressComponent;
          this.ruleForm.regeocode.adcode = addressComponent.adcode
          this.ruleForm.regeocode.province = addressComponent.province
          this.ruleForm.regeocode.city = addressComponent.city == '' ? addressComponent.province : addressComponent.city
          this.ruleForm.regeocode.district = addressComponent.district;

          let cityName = this.isUseNearBy ? '' : this.handleCityName;
          if(this.isUseNearBy) {
            this.placeSearch.searchNearBy(cityName, this.center, 1000, (status, result) => {
              this.searchCallBack(status, result, e)
            });
          } else {
            this.placeSearch.search(cityName, (status, result, e) => {
              this.searchCallBack(status, result)
            });
          }
        } else {
          this.emptyLocationData();
        }
      })
    },
    searchCallBack(status, result, event) {
      if (status === 'complete' && result.poiList.pois.length) {
        if(event) {
          this.lists = result.poiList.pois;
          if(this.lists.length % this.pageSize !== 0) {
            this.bottomLineShow = true;
          } else {
            this.bottomLineShow = false;
          }
          this.getAddress(0);
          if(this.scroll) {
            this.scroll.scrollTo(0, 0);
            this.scroll.finishPullUp();
          } else {
            this._initScroll();
          }
          this.addMarker();
        } else {
          this.lists = concat(this.lists, result.poiList.pois);
          if(this.lists.length % this.pageSize !== 0) {
            this.bottomLineShow = true;
          } else {
            this.bottomLineShow = false;
          }
          this.originalStatus();
        }
      } else {
        this.bottomLineShow = true;
      }
    },

主要的部分就是上面这些,还有一些里面用到的方法,我截几张图吧,第一次写文章,写的比较乱。
创建地图。

地图添加marker

地图信息窗体

自定义信息窗体dom结构


文心雕刺
144 声望3 粉丝