一,前言

需求: 省市区三级联动 下拉选择出数据 并地图显示位置,地图上选择定位位置 三级联动反显出 省市区;

准备:

1.需要 全国地址完整(省市区-地区code)的 area.json,

百度云盘 下载地址  提取码:ufyz (另本已上传csdn资源,设置了几次0c币,但是系统一直自动给改要4-8C币,已弃)

2. 地址定位 这里用的是 高德api 故需要申请高德web开发相关申请配置 见这篇

二,实现

1.utils.js 自用工具类

 @utils/area/index 是标题一 内放置的 area-index.js 资源,自己项目使用自己的资源路径

/**
 * @param arr 城市地址三级联动选择器,选择出的code 数组
 * @return 返回解析出 省-市-区/县 的名字 addObj对象
 */
import AreaData from '@/utils/area/index'
export function areaCode2AreaName(arr) {
  // console.log('areaCode2AreaName()-code名转地址', arr)
  const [provinceCode, cityCode, countyCode] = arr
  let _province, _city, _county
  const _areaData = AreaData
  let addObj = {}
  if (_areaData.length > 0) {
    for (const k in _areaData) {
      if (_areaData[k].value === provinceCode) {
        _province = _areaData[k].label
        const _areaData2 = _areaData[k].children
        for (const k2 in _areaData2) {
          if (_areaData2[k2].value === cityCode) {
            _city = _areaData2[k2].label
            const _areaData3 = _areaData2[k2].children
            for (const k3 in _areaData3) {
              if (_areaData3[k3].value === countyCode) {
                _county = _areaData3[k3].label
                break
              }
            }
          }
        }
      }
    }
  }
  addObj = {
    province: _province,
    city: _city,
    county: _county
  }
  return addObj
}
/**
 * @param arr 城市地址三级联动选择器,选择出的code 数组
 * @return 返回解析出 省-市-区/县 的code编码 addObj对象
 */
export function areaName2AreaCode(arr) {
  // console.log('areaName2AreaCode()-地址名转code', arr)
  const [provinceName, cityName, countyName] = arr
  let _province, _city, _county
  const _areaData = AreaData
  let addObj = {}
  if (_areaData.length > 0) {
    for (const k in _areaData) {
      if (_areaData[k].label === provinceName) {
        _province = _areaData[k].value
        // console.log('areaName2AreaCode()-地址名转code-_province', _province)
        // 重庆市 500000   ,北京市 110000 ,  上海市 310000,  天津市 120000, 香港特别行政区  810000,  澳门特别行政区 820000
        if (_province === '500000' || _province === '110000' || _province === '310000' || _province === '120000'|| _province === '810000' || _province === '820000') {
          const _areaData2 = _areaData[k].children
          let now_cityName = provinceName
          if (provinceName === '香港特别行政区' || provinceName === '澳门特别行政区') {
            now_cityName = provinceName.replace('特别行政区', '')
          }
          for (const k2 in _areaData2) {
            if (_areaData2[k2].label === now_cityName) {
              _city = _areaData2[k2].value
              const _areaData3 = _areaData2[k2].children
              for (const k3 in _areaData3) {
                 // 兼容处理 countyName输入的值中有 XX新区 及 XX区 这种值不确定 不匹配问题
                let countCountyName = ''
                if (countyName.indexOf('新区') !== -1) {
                  countCountyName = countyName.substring(0, countyName.indexOf('新区'))
                } else {
                  countCountyName = countyName
                }
                if (_areaData3[k3].label.indexOf(countCountyName) !== -1) {
                  _county = _areaData3[k3].value
                  break
                }
              }
            }
          }
        } else {
          const _areaData2 = _areaData[k].children
          for (const k2 in _areaData2) {
            if (_areaData2[k2].label === cityName) {
              _city = _areaData2[k2].value
              const _areaData3 = _areaData2[k2].children
              for (const k3 in _areaData3) {
                 // 兼容处理 countyName输入的值中有 XX新区 及 XX区 这种值不确定 不匹配问题
                let countCountyName = ''
                if (countyName.indexOf('新区') !== -1) {
                  countCountyName = countyName.substring(0, countyName.indexOf('新区'))
                } else {
                  countCountyName = countyName
                }
                if (_areaData3[k3].label.indexOf(countCountyName) !== -1) {
                  _county = _areaData3[k3].value
                  break
                }
              }
            }
          }
        }
      }
    }
  }
  addObj = {
    provinceCode: _province,
    cityCode: _city,
    countyCode: _county
  }
  return addObj
}

// String: null => ''
export function stringNullToValue(string) {
  let nowStr = ''
  if (string) {
    nowStr = string
  }
  return nowStr
}

2. positionLocation.js 高德地图定位 经纬度转地址

/**
 * CopyRight zh
 * 2020/03/31
 * positionLocation.js
 * version : 1.0.0
 */
'use strict'
// import Vue from 'vue'
// import AMap from 'AMap'
// Vue.use(AMap)
import Axios from 'axios'
/**
 * @param address 详细地址  省-市-区
 * @param callback 回调函数 返回resData
 * @return resData: {
 *    status: true, // 是否成功
      data: null, // 返回数据
      message: null, // 返回提示信息
 *  }
 * */
export function getLngLat(address, callback) {
  console.log('getLngLat()-',address)
  const resData = {
    status: true,
    data: null,
    message: null,
  }
  // 根据地址获取经纬度
  Axios.get('https://restapi.amap.com/v3/geocode/geo?key=这里放自己的高德密钥&&address='+address).then(res=>{
    if(res.status ===200 && res.data.info==='OK'){
      let resp = res.data.geocodes[0]
      // console.error("getLngLat()-resp", resp)
      if(resp){
        resData.data = resp.location.split(',')
        resData.message = '获取经纬度成功'
        callback(resData)
      }else {
        console.error("不存在该位置信息")
        resData.status = false
        resData.message = '不存在该位置信息'
        callback(resData)
      }
    }else {
      console.error("获取经纬度信息失败")
      resData.status = false
      resData.message = '获取经纬度信息失败'
      callback(resData)
    }
  })
}

/**
 * @param longitude  经度 英文:longitude  114.044815
 * @param latitude 纬度 英文:latitude   22.687373
 * @param callback 回调函数 返回resData
 * @return resData: {
 *    status: true, // 是否成功
      data: null, // 返回数据
      message: null, // 返回提示信息
 *  }
 * */
export function getLocation(longitude, latitude, callback){
  // const that = this
  const location = longitude + ',' + latitude
  console.log('getLocation()-location',location)
  const resData = {
    status: true,
    data: null,
    message: null,
  }
  const nowLocation = {
    lat: '', // 纬度
    lon: '', // 经度
    province: '', // 省
    city: '', // 市
    district: '', // 区 县
    street: '', // 街道、乡镇
    nowPlace: '', // 省-市-区
    addressDetail: '' // 详细地址
  }
  // 根据经纬度获取地址
  Axios.get('https://restapi.amap.com/v3/geocode/regeo?key=这里放自己的高德密钥&location='+location).then(res=>{
    if(res.status === 200 && res.data.info==='OK'){
      let resp= res.data.regeocode.addressComponent
      const addressDetails = res.data.regeocode.formatted_address
      // console.log('getLocation()-resp',resp)
      if(resp){
        nowLocation.province = resp.province
        if(resp.province ==='上海市'||resp.province ==='重庆市'||resp.province ==='天津市'||resp.province ==='北京市'||resp.province ==='香港特别行政区'||resp.province ==='澳门特别行政区'){
          if (resp.province === '香港特别行政区' || resp.province === '澳门特别行政区') {
            nowLocation.city = resp.province.replace('特别行政区', '')
          } else {
            nowLocation.city = resp.province
          }
        } else {
          nowLocation.city = resp.city
        }
        // 如果例如: 东莞市-虎门镇 返回信息 district 值为 [], 则 东莞市 区级值  用 township街道值 进行回填
        // console.log('resp.district instanceof Array', resp.district instanceof Array)
        if (resp.district instanceof Array && resp.district.length === 0) {
          nowLocation.district = resp.township
        } else {
          nowLocation.district = resp.district
        }
        nowLocation.street = resp.township
        nowLocation.nowPlace = nowLocation.province + nowLocation.city + nowLocation.district
        nowLocation.lon = longitude
        nowLocation.lat = latitude
        nowLocation.addressDetail = resp.neighborhood.name
        if (resp.district !== false){
          nowLocation.addressDetail = addressDetails.split(resp.district)[1]
        }else if(resp.city !== false){
          nowLocation.addressDetail = addressDetails.split(resp.city)[1]
        }
        resData.data = nowLocation
        resData.message = '获取位置信息成功'
        callback(resData)
      } else {
        console.error("不存在该位置信息")
        resData.status = false
        resData.message = '不存在该位置信息'
        callback(resData)
      }
    }else {
      console.error("获取地址信息失败")
      resData.status = false
      resData.message = '获取地址信息失败'
      callback(resData)
    }
  })
}

3.这里是 页面vue

<template>
 <!-- 省市区三级联动 -->
 <el-form label-width="110px" ref="objEditFrom" :model="objEditData">
   <el-form-item label="发生地点" prop="selectedOptionsStart">
            <el-cascader
              class="w184"
              placeholder="任意搜索地区"
              :options="areaData"
              filterable
              change-on-select
              @change="startAddressChange"
              v-model="objEditData.selectedOptionsStart"
            ></el-cascader>
          </el-form-item>
          <el-form-item label="街道/乡镇" prop="street">
            <el-input type="text" clearable v-model="objEditData.street" class="w184" @change="detailChange"></el-input>
          </el-form-item>
          <el-form-item label="详细地址" prop="addressDetails">
            <el-input type="text" clearable v-model="objEditData.addressDetails" 
             class="w184" @change="detailChange"></el-input>
          </el-form-item>
</el-from>
 <!-- 地图 -->
 <div>
   <!-- 地图容器 -->
   <div id="amap-container" style="width:400px;height: 300px;"></div>
</div>
</template>
<style>
.w184{
  width: 184px!important;
}
</style>

<script>
  import Area from "@/utils/area/index";
  import * as Utils from "@/utils/index";
  import * as LocationAMap from "@/utils/positionLocation/positionLocation";
  export default {
    data() {
      return {
        objEditData: {
          selectedOptionsStart: ["", "", ""], // 省市区 编码
          addressDetails: null, // 出险地点 详细地址
          longitude: null,
          latitude: null
        },
        areaData: Area, // 省-市-区三级联动选择
        selectArea: {
         province: '',
         city: '',
         county: '',
         street: '',
         addressDetails: ''
        },
      }
    },
    mounted() {
      // this.initFunc();
    },
    methods: {
      initFunc() {
        const that = this;
        const province = '广东省'
        const city = '深圳市'
        const county = '南山区'
        const street= '西乡街道'
        const addressDetails = '详细地址'
        // 解析 省市区 编码
        const { provinceCode, cityCode, countyCode } = Utils.areaName2AreaCode([province, city, county]);
        // 如果是编辑 已有 省 市 区 数据进行设置 三级联动显示对应 省市区
        that.objEditData = {
          selectedOptionsStart: [provinceCode, cityCode, countyCode],
          addressDetails
        }
        that.selectArea = {province, city, county, street, addressDetails}
        that.getLngLatFunc(); // 地址转经纬度
      },
      initMap(longitude, latitude,zoom) {
        console.log("initMap()初始化");
        const that = this;
        // const newV = [116.397559, 39.89621]
        //   center: new AMap.LngLat(nowLog, nowLat),
        const nowLog = longitude || 116.397559;
        const nowLat = latitude || 39.89621;
        let zoomdata= zoom?zoom:11
        const mapObj = new AMap.Map("amap-container", {
          center: [nowLog, nowLat],
          zoom: zoomdata // 初始化地图时显示的地图放大等级
        });
        // console.log("initMap()初始化-nowLog", nowLog, nowLat);
        const markerNow = {
          name: "",
          lnglat: [nowLog, nowLat]
        };
        createMarkerFunc(markerNow);
        // 地图点击事件
        const showInfoClick = function(e) {
          console.log("showInfoClick()触发了地图click事件-e");
          // e.lnglat.getLng(),e.lnglat.getLat()
          const markerItem = {
            name: "",
            lnglat: [e.lnglat.getLng(), e.lnglat.getLat()]
          };
          createMarkerFunc(markerItem);
          setBoundsFunc(markerItem);
          that.getLocationFunc(e.lnglat.getLng(), e.lnglat.getLat());
        };
        // 监听 地图点击事件
        // if (!that.makeInputDisabled) {
        //   mapObj.on("click", showInfoClick);
        // }
        mapObj.on("click", showInfoClick);
        // -------------自定义方法------------------
        // 指定当前地图显示范围,参数bounds为指定的范围
        function setBoundsFunc(markerItem) {
          console.log("setBoundsFunc()");
          const start = [
            Number(markerItem.lnglat[0]) - 0.01,
            Number(markerItem.lnglat[1]) - 0.01
          ];
          const end = [
            Number(markerItem.lnglat[0]) + 0.01,
            Number(markerItem.lnglat[1]) + 0.01
          ];
          const mybounds = new AMap.Bounds(start, end);
          mapObj.setBounds(mybounds);
        }
        // 创建Marker方法
        function createMarkerFunc(markerItem) {
          console.log("createMarker()");
          mapObj.clearMap(); // 清除地图覆盖物
          // 创建一个 Marker 实例:
          const marker = new AMap.Marker({
            map: mapObj,
            position: new AMap.LngLat(markerItem.lnglat[0], markerItem.lnglat[1])// 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
          });
          // 将创建的点标记添加到已有的地图实例:
          mapObj.add(marker);
        }
      },
  //  街道/ 乡镇 、详细地址 修改时
    detailChange() {
      this.selectArea.street = this.objEditData.street
      this.selectArea.addressDetails = this.objEditData.addressDetails
      this.getLngLatFunc()
    },
      // 通过 地址 获取 经纬度
      getLngLatFunc() {
        const that = this;
const { province, city, county, street, addressDetails } = that.selectArea;
      const address = Utils.stringNullToValue(province) + Utils.stringNullToValue(city) + Utils.stringNullToValue(county) + Utils.stringNullToValue(street) + Utils.stringNullToValue(addressDetails);
        LocationAMap.getLngLat(address, function(resData) {
          if (resData.status) {
            console.log("getLngLatFunc()-", resData.data);
            that.LngLat = resData.data;
            that.objEditData.longitude = that.LngLat[0];
            that.objEditData.latitude = that.LngLat[1];
            // 解决 地图 异步渲染问题
            that.$nextTick(() => {
              that.initMap(that.objEditData.longitude, that.objEditData.latitude);
          });
          } else {
            that.$message({
              message: resData.message,
              type: "warning",
              duration: 2000
            });
          }
        });
      },
      // 通过经纬度获取 地址
      getLocationFunc(longitude, latitude) {
        const that = this;
        // const location = longitude + ',' + latitude
        // console.log('getLocationFunc()-location',location)
        LocationAMap.getLocation(longitude, latitude, function(resData) {
          if (resData.status) {
            const { province, city, district, addressDetail, street } = resData.data;
            that.selectArea = {
              province: province,
              city: city,
              county: district,
              street: street,
              addressDetails: addressDetail
            };
            // 解析 省市区 编码
            const {
              provinceCode,
              cityCode,
              countyCode
            } = Utils.areaName2AreaCode([province, city, district]);
            that.objEditData.selectedOptionsStart = [
              provinceCode,
              cityCode,
              countyCode
            ];
            that.objEditData.addressDetails = addressDetail;
            that.objEditData.longitude = longitude;
            that.objEditData.latitude = latitude;
          } else {
            this.$message({
              message: resData.message,
              type: "warning",
              duration: 2000
            });
          }
        });
      },
      // 三级连选 起运地地址
      startAddressChange(val) {
        const selectArr = val;
        console.log("startAddressChange()-val", val);
        this.selectArea = Utils.areaCode2AreaName(selectArr);
        this.getLngLatFunc();
      }
    }
  }
</script>

4.实现效果截图

选择省市区 或 详细地址-地图显示标记位置

地图选择定位-反显省市区三级联动+详细地址

Logo

前往低代码交流专区

更多推荐