vue使用高德地图搜索地址添加标记marker,定位,拖拽选址功能

2,856 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

实现效果: 需求:点击输入框弹窗地图弹窗,输入框输入地址模糊搜索列表结果,点击列表添加相应得marker标记,并且添加标记拖拽选址功能。 e2bf487cb2cb412ca5feff3103849489.png  watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Ii56ZW_5Zyo6Ii55LiK,size_20,color_FFFFFF,t_70,g_se,x_16

项目中引入了 element-ui ,自行安装引入,这里不写了......

JSAPI 的加载

JS API 2.0 版本提供了两种方案引入地图 JSAPI:

  1. 使用官网提供的 JSAPI Loader 进行加载;

  2. 以常规 JavaScript 脚本的方式加载;

注意:为避免地图数据协议和前端资源不匹配导致页面运行报错,只允许在线加载 JSAPI,禁止进行本地转存、与其它代码混合打包等用法。

使用 JSAPI Loader (推荐)

JSAPI Loader是我们提供的 API 加载器,可帮助开发者快速定位、有效避免加载引用地图 JSAPI 各种错误用法,具有以下特性:

支持以 普通JS 和 npm包 两种方式使用; 有效避免错误异步加载导致的 JSAPI 资源加载不完整问题; 对于加载混用多个版本 JSAPI 的错误用法给予报错处理; 对于不合法加载引用 JSAPI 给予报错处理; 支持指定 JSAPI 版本; 支持插件加载; 允许多次执行加载操作,网络资源不会重复请求,便于大型工程模块管理; 支持IE9以上的浏览器,不支持IE8以下 注意(您在2021年12月02日申请以后的key需要配合您的安全密钥一起使用)

JSAPI key和安全密钥的使用

JSAPI key搭配代理服务器并携带安全密钥转发(安全)

1) 引入 JSAPI 使用 Loader 之前增加代理服务器设置脚本标签,设置代理服务器域名或地址,将下面示例代码中的「您的代理服务器域名或地址」替换为您的代理服务器域名或ip地址,其中_AMapService为代理请求固定前缀,不可省略或修改。 (注意您这 个设置必须是在加载loader.js的脚本引入之前进行设置,否则设置无效。)

项目代码步骤:

1、在index.html页面body中添加秘钥

<body>
    <noscript>
      <strong>We're sorry but map-demo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <script type="text/javascript">
      window._AMapSecurityConfig = {
          // serviceHost:'您的代理服务器域名或地址/_AMapService',  
          securityJsCode:"xxxxxx"//申请的秘钥
      }
    </script>
  </body>
......

2、安装@amap/amap-jsapi-loader 使用

npm i @amap/amap-jsapi-loader --save

3、重要代码:

  <div class="positionBox">
    <el-input style="width:600px;margin:100px 0 0 100px;" v-model="positionVal" placeholder="请输入内容" @focus="handleOpen"></el-input>
    <div class="wrapper" v-show="dialogVisible">
      
      <div class="mapcontainer">
        <div class="el-dialog__header">
          <button type="button" aria-label="Close" class="el-dialog__headerbtn" @click="handleClose">
            <i class="el-dialog__close el-icon el-icon-close" style="font-size:25px;"></i>
            </button>
        </div>
        <div class="mapContent">
          <div id="all" style="height: 100%">
            <div class="posInput">
              <el-input
                style="width: 100%"
                id="tipinput"
                class="form-control input-style"
                type="text"
                placeholder="请输入搜索地址"
                prefix-icon="el-icon-search"
                v-model="MapAdress"
              >
              </el-input>
            </div>
            <div id="allmap"></div>
            <div class="posSubmit">
              <el-form ref="form" label-width="100px">
                <div class="btn_box">
                  <el-form-item label="地址坐标:" style="width:45%">
                    <el-input disabled type="text" v-model="insureAdress" >
                    </el-input>
                  </el-form-item>
                  <el-form-item label="经纬度:" style="width:45%">
                    <el-input disabled type="text" v-model="insureAdress2" >
                    </el-input>
                  </el-form-item>
                  <el-form-item>
                    <el-button type="primary" size="large" style="margin-left: 10px" @click="insureMapAdress">确定</el-button>
                  </el-form-item>
                </div>
              </el-form>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import AMapLoader from "@amap/amap-jsapi-loader";
export default {
  name: "app",
  data() {
    return {
      dialogVisible:false,
      positionVal:"",
      map: null,
      marker: null,
      geocoder: null, // 地理编码与逆地理编码类,用于地址描述与坐标之间的转换
      startAutoComplete: null,
      startPlaceSearch: null,
      positionPicker: null,
      startSeacrh: [],
      stratInfo: {},
 
      thisPosition: {
        location: "",
        lng: "",
        lat: "",
      },
      mapinitCode: 0, //地理编码:1;地理逆编码:2
      MapAdress: "",
      insureAdress: "",
      insureAdress2: "",
    };
  },
  mounted() {
    // this.loadmap();//因为使用的弹窗加载,所以这里不用执行了,在打开弹窗时候在调用此方法
  },
  methods: {
    loadmap() {
      const that = this;
      return new Promise((reslove, reject) => {
        AMapLoader.load({
          key: "xxxxxx", // 申请好的Web端开发者Key,首次调用 load 时必填
          // version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
          plugins: ["AMap.ToolBar","AMap.Scale", "AMap.Geocoder"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
          AMapUI: {
            // 是否加载 AMapUI,缺省不加载
            version: "1.1", // AMapUI 缺省 1.1
            plugins: [], // 需要加载的 AMapUI ui插件
          },
        }).then((AMap) => {
            that.map = new AMap.Map("allmap", {
              resizeEnable: true,
              zoom: 10,
              center: [116.397428, 39.90923], //中心点坐标
            });
            // 地图点击事件
            // that.map.on("click", (e) =>{
            //   let lnglatXY = [e.lnglat.getLng(), e.lnglat.getLat()];
            //   console.log(lnglatXY)//当前经纬度
            // })
 
            //地图控件
            that.map.addControl(new AMap.Scale());
            that.map.addControl(new AMap.ToolBar());
            // that.map.setMapStyle("amap://styles/blue")
            // that.map.setMapStyle("amap://styles/darkblue")
            // 地理编码与逆地理编码类,用于地址描述与坐标之间的转换
            that.geocoder = new AMap.Geocoder();
            //地点查询
            AMap.plugin(["AMap.PlaceSearch", "AMap.Autocomplete"], function () {
              let autoOptions1 = { 
                input: "tipinput", 
                city: "全国" 
              };
              that.startAutoComplete = new AMap.Autocomplete(autoOptions1);
              that.startPlaceSearch = new AMap.PlaceSearch({
                map: that.map,
              });
              that.startAutoComplete.on("select", that.handleStartSelect); //注册监听,当选中某条记录时会触发
            });
            that.handlePositionPickerEvent(); //实现地图拖拽选址功能
 
            that.map.setZoom(14);//设置缩放大小
 
            reslove();
          }).catch((e) => {
            console.log(e, "高德地图加载失败");
            reject(e);
          });
      });
    },
    handlePositionPickerEvent() {
      let that = this;
      AMapUI.loadUI(["misc/PositionPicker"], (PositionPicker) =>{
        console.log("拖拽加载成功");
        that.positionPicker = new PositionPicker({
          // mode: 'dragMap',//拖拽地图
          mode: "dragMarker",//拖拽图标
          map: that.map,
        });
 
        that.positionPicker.on("success", (positionResult)=> {
          console.log(positionResult, "拖拽信息");
          console.log(positionResult.position,"拖拽经纬度")
 
          if(positionResult.address){
            this.insureAdress = positionResult.address;
            this.insureAdress2 = "[" + positionResult.position + "]"
          }else{
            this.insureAdress="";
            this.insureAdress2 = "";
          };
 
        });
        that.positionPicker.on("fail", (positionResult) =>{
          // 海上或海外无法获得地址信息
        });
      });
    },
    handleStartSelect(event) {
      console.log(event, "起点经纬度 [lng,lat]");
      if (event.poi.location == "") {
        this.$message({
          type: "warning",
          message: "该地点无经纬度数据,请输入具体一点的地点!",
          duration: 5 * 1000,
        });
        return;
      }
      if (this.marker) {
        this.map.remove(this.marker);
        this.marker = null;
      }
      this.startSeacrh = [];
      this.stratInfo = {};
      this.startSeacrh = [event.poi.location.lng, event.poi.location.lat];
      this.stratInfo = {
        district: event.poi.district,
        address: event.poi.address,
        name: event.poi.name,
      };
      this.insureAdress = event.poi.district + event.poi.address + event.poi.name;
      this.insureAdress2 = "[" + event.poi.location.lng + "," + event.poi.location.lat + "]";
 
      // marker添加地图上
      // this.marker = new AMap.Marker({
      //   position: this.startSeacrh, //位置
      // });
      // this.map.add(this.marker); //添加到地图
 
      // 传入经纬度,设置地图中心点
      this.map.setCenter(this.startSeacrh);
      this.positionPicker.start(this.startSeacrh);  //启动这句控制 地图出现一个maker点,可以移动
      // this.positionPicker.stop();   //取消移动的maker
      this.map.setZoom(15);
 
      // 添加自定义弹窗
      // this.addDialog(this.insureAdress);
    },
    addDialog(address){
      this.map.setCenter(this.startSeacrh);
      this.marker.content = address;
      this.marker.on('click', this.markerClick);
      this.marker.emit('click', {target: this.marker});
    },
    markerClick(e){
      let infoWindow = new AMap.InfoWindow({offset: new AMap.Pixel(0, -30)});
      infoWindow.setContent(e.target.content);
      infoWindow.open(this.map, e.target.getPosition());
    },
    insureMapAdress() {
      //确定地址
      this.positionVal = this.insureAdress;
      this.dialogVisible = false;
      this.MapAdress = "";
      this.insureAdress = "";
      this.insureAdress2 = "";
      this.positionPicker.stop();   //取消移动的maker
    },
 
    maplocal(address) {
      //地理逆编码
      this.geocoder.getLocation(address, (status, result) => {
        console.log(address);
        if (status === "complete" && result.geocodes.length) {
          console.log(result);
          const lnglat = result.geocodes[0].location;
 
          const lat = lnglat.lat;
          const lng = lnglat.lng;
          that.mapinit(lat, lng); //tips:使用地理逆编码,此时解析出的经纬度位置也应逆换
        } else {
          console.log(result);
        }
      });
    },
    handleOpen(){
      this.dialogVisible = true;
      this.loadmap();
    },
    handleClose(){
      this.dialogVisible = false;
      this.MapAdress = "";
      this.insureAdress = "";
      this.insureAdress2 = "";
      this.positionPicker.stop();   //取消移动的maker
    }
  },
};
</script>
<style scoped>
.mapContent{
  /* position: absolute;
  left:0;
  top:0;
  width:100%; */
  height:460px;
}
#all {
  position: relative;
}
#allmap {
  width: 100%;
  height: calc(100% - 50px);
  font-family: "微软雅黑";
}
.posInput {
  position: absolute;
  z-index: 1;
  width: 80%;
  margin-top: 20px;
  margin-left: 10%;
}
::v-deep .el-form-item {
  margin-bottom: 0 !important;
}
.btn_box{
  display: flex;
}
/* 去除高德水印 */
::v-deep .amap-logo {
  display: none;
  opacity: 0 !important;
}
::v-deep .amap-copyright {
  opacity: 0;
}
.wrapper{
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: rgb(0 0 0 / 30%);
}
.mapcontainer{
  position: absolute;
  left:50%;
  top:50%;
  width:80%;
  height:460px;
  transform: translate(-50%,-50%);
  background: #fff;
  padding:50px;
}
</style>