vue 结合 element-ui 实现 pc 端高德地图组件

背景:去年由于业务需求写了一个高德地图组件,前段时间重构了下。

实现的功能有:自动定位,检索地址提示,点击地图获取地址,添加工具栏,拿到的数据有经纬度,地址,名称等

项目依赖:vue-cli:3.5.3 vue:2.6.10 element-ui: ^2.7.0 等

使用步骤

1./public/index.html 文件中导入高德地图 js

1
<script
2
  type="text/javascript"
3
  src="https://webapi.amap.com/maps?v=1.4.4&key=<%=VUE_APP_AMAP_KEY%>"
4
></script>

2.环境变量中配置地图 key 值(也可以直接写在上面,就是不便于维护)

.env.development 和.env.production 文件中加入

1
VUE_APP_AMAP_KEY=''  #  你的高德地图key值

3.地图组件 /components/Amap/index.vue

1
<template>
2
  <div id="amap-container">
3
    <el-input
4
      id="search-input"
5
      v-model="searchValue"
6
      class="input-with"
7
      placeholder="请输入地址"
8
      clearable
9
      @clear="handelclearInput"
10
      @keyup.native.enter="handelSearch"
11
    >
12
      <el-button
13
        slot="append"
14
        size="small"
15
        type="primary"
16
        icon="el-icon-search"
17
        @click="handelSearch"
18
        >搜索</el-button
19
      >
20
    </el-input>
21
22
    <div id="searchResultPanel" />
23
    <el-row class="margin-top-10 address">
24
      当前地址是: {{ formattedAddress }}
25
      <el-button size="small" type="primary" @click="handelSave"
26
        >使用该地址</el-button
27
      >
28
    </el-row>
29
30
    <div id="custom-amap" />
31
  </div>
32
</template>
33
34
<script>
35
  const AMap = window.AMap;
36
  export default {
37
    name: "AMap",
38
    props: {
39
      defaultValue: {
40
        type: String,
41
        default: ""
42
      }
43
    },
44
    data() {
45
      return {
46
        defaultCity: "北京",
47
        // 地图对象
48
        map: null,
49
        // 定位默认地址 | 搜索后选择的地址
50
        formattedAddress: null,
51
        // 地址对应的经纬度信息
52
        position: {},
53
        // 检索关键字
54
        searchValue: "",
55
        // 检索函数对象
56
        placeSearch: null,
57
        // 检索结果数据数据
58
        searchInfoList: [],
59
        // 地图标记
60
        marker: "",
61
        // 地址解析(正向)
62
        geocoder: "",
63
        // 地址名称
64
        name: ""
65
      };
66
    },
67
    watch: {
68
      defaultValue() {
69
        this.searchValue = this.defaultValue;
70
      }
71
    },
72
    mounted() {
73
      // 初始化地图页面
74
      this.initMap();
75
    },
76
    beforeDestroy() {
77
      // 销毁地图
78
      this.map.destroy();
79
    },
80
    methods: {
81
      //   初始化地图页面
82
      initMap() {
83
        this.map = new AMap.Map("custom-amap", {
84
          resizeEnable: true,
85
          zoom: 50
86
        });
87
        // 添加工具栏
88
        this.map.plugin(["AMap.ToolBar", "AMap.Scale", "AMap.OverView"], () => {
89
          // 工具条
90
          const toolbar = new AMap.ToolBar();
91
          // 比例尺
92
          const scale = new AMap.Scale();
93
          // 显示鹰眼
94
          const overView = new AMap.OverView();
95
          this.map.addControl(toolbar);
96
          this.map.addControl(scale);
97
          this.map.addControl(overView);
98
        });
99
        // 添加maker
100
        this.setMaker();
101
        // 添加鼠标点选地图选择地址
102
        this.addAmapGeocoder();
103
        // 添加定位
104
        this.addAMapGeolocation();
105
        // 添加检索提示
106
        this.addAMapAutocompletePlaceSearch();
107
      },
108
      // 添加maker
109
      setMaker() {
110
        this.marker = new AMap.Marker();
111
        this.map.add(this.marker);
112
        // 添加解析地理位置插件
113
        this.map.plugin("AMap.Geocoder", () => {
114
          // 异步加载插件
115
          this.geocoder = new AMap.Geocoder({
116
            city: this.defaultCity, // 默认:“全国”
117
            radius: 1000 // 范围,默认:500
118
          });
119
        });
120
      },
121
      // 添加鼠标点选地图选择地址
122
      addAmapGeocoder() {
123
        // 添加maker
124
        this.setMaker();
125
        // 地图添加点击事件
126
        this.map.on("click", e => {
127
          const lnglat = [e.lnglat.lng, e.lnglat.lat];
128
          this.marker.setPosition(lnglat);
129
          this.geocoder.getAddress(lnglat, (status, result) => {
130
            if (status === "complete" && result.regeocode) {
131
              const res = result.regeocode;
132
              const data = {
133
                // 地址名称
134
                adress: res.formattedAddress,
135
                // 纬度lat
136
                lat: lnglat[1],
137
                // 经度lng
138
                lng: lnglat[0]
139
              };
140
              this.formattedAddress = res.formattedAddress;
141
              this.position = data;
142
            } else {
143
              alert(JSON.stringify(result));
144
            }
145
          });
146
        });
147
      },
148
      // 添加自动定位
149
      addAMapGeolocation() {
150
        this.map.plugin("AMap.Geolocation", () => {
151
          const geolocation = new AMap.Geolocation({
152
            // 是否使用高精度定位,默认:true
153
            enableHighAccuracy: true,
154
            // 设置定位超时时间,默认:无穷大
155
            timeout: 10000,
156
            // 定位按钮的停靠位置的偏移量,默认:Pixel(10, 20)
157
            buttonOffset: new AMap.Pixel(200, 200),
158
            //  定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
159
            zoomToAccuracy: true,
160
            //  定位按钮的排放位置,  RB表示右下
161
            buttonPosition: "RB"
162
          });
163
          // 获取当前位置
164
          geolocation.getCurrentPosition();
165
          // 添加定位当前城市成功监听
166
          AMap.event.addListener(
167
            geolocation,
168
            "complete",
169
            this.onCurrentPositionComplete
170
          );
171
          // 添加定位当前城市发生错误监听
172
          AMap.event.addListener(
173
            geolocation,
174
            "error",
175
            this.onCurrentPositionError
176
          );
177
        });
178
      },
179
      // 添加检索提示检索
180
      addAMapAutocompletePlaceSearch() {
181
        // 自动提示
182
        this.map.plugin("AMap.Autocomplete", () => {
183
          const auto = new AMap.Autocomplete({
184
            city: this.defaultCity,
185
            input: "search-input"
186
          });
187
          // 添加检索监听
188
          AMap.event.addListener(auto, "select", this.onSelectAutocomplete);
189
        });
190
        // 检索服务
191
        AMap.service(["AMap.PlaceSearch"], () => {
192
          // 构造地点查询类
193
          this.placeSearch = new AMap.PlaceSearch({
194
            type: "", // 兴趣点类别
195
            pageSize: 5, // 单页显示结果条数
196
            pageIndex: 1, // 页码
197
            city: this.defaultCity, // 兴趣点城市
198
            citylimit: false, // 是否强制限制在设置的城市内搜索
199
            map: this.map, // 展现结果的地图实例
200
            panel: "searchResultPanel", // 结果列表将在此容器中进行展示。
201
            autoFitView: true // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见范围
202
          });
203
        });
204
        // 添加检索监听
205
        AMap.event.addListener(
206
          this.placeSearch,
207
          "listElementClick",
208
          this.onSelectSearch
209
        );
210
      },
211
      // 定位当前城市成功回调
212
      onCurrentPositionComplete(res) {
213
        // 添加maker
214
        this.setMaker();
215
        const lnglat = [res.position.lng, res.position.lat];
216
        this.marker.setPosition(lnglat);
217
        console.log(res, "res");
218
        this.formattedAddress = res.formattedAddress;
219
        this.position = res.position;
220
      },
221
      // 定位当前城市发生错误回调
222
      onCurrentPositionError(err) {
223
        console.log(err);
224
      },
225
      // 按钮触发检索
226
      handelSearch() {
227
        this.placeSearch.search(this.searchValue, (status, info) => {
228
          this.searchInfoList = info.poiList.pois;
229
        });
230
      },
231
      // 选择自动提示数据事件回调
232
      onSelectAutocomplete(e) {
233
        this.searchValue = e.poi.name;
234
        this.handelSearch();
235
      },
236
      // 选择检索数据结果事件回调
237
      onSelectSearch(e) {
238
        const res = e.data;
239
        this.formattedAddress = res.cityname + res.adname + res.address;
240
        this.name = res.name;
241
        this.position = res.location;
242
      },
243
      // 清除input里的值,清除搜索结果,再次初始化map
244
      handelclearInput() {
245
        document.querySelector("#searchResultPanel").innerHTML = "";
246
      },
247
      // 保存当前选择的地址,分发事件
248
      handelSave() {
249
        this.searchValue = this.formattedAddress;
250
        const { lat, lng } = this.position;
251
        const data = {
252
          name: this.name,
253
          // 地址名称
254
          address: this.formattedAddress,
255
          // 纬度lat
256
          lat,
257
          // 经度lng
258
          lng
259
        };
260
        this.$emit("getPosition", data);
261
      }
262
    }
263
  };
264
</script>
265
266
<style lang="scss">
267
  #amap-container {
268
    .el-input__clear {
269
      line-height: 34px;
270
      // top: 20px;
271
    }
272
    #custom-amap {
273
      height: 60vh;
274
      width: 100%;
275
      margin-top: 10px;
276
      border: 1px solid #ccc;
277
    }
278
    .input-with {
279
      // position: fixed;
280
      // top: 40px;
281
      z-index: 1;
282
      width: 580px;
283
    }
284
    .address {
285
      color: #373737;
286
    }
287
  }
288
  .amap-sug-result {
289
    z-index: 99999;
290
  }
291
</style>

4.使用

1
<template>
2
  <amap :default-value="postForm.detailedAddress" @getPosition="getPosition" />
3
</template>
4
<script>
5
  import Amap from "@/components/Amap";
6
  export default {
7
    components: {
8
      Amap
9
    },
10
    data: {
11
      postForm: {
12
        detailedAddress: "",
13
        longitude: "",
14
        latitude: ""
15
      }
16
    },
17
    methods: {
18
      // 获取地址信息
19
      getPosition({ address, lat, lng, name }) {
20
        this.postForm.detailedAddress = address;
21
        this.postForm.longitude = String(lng);
22
        this.postForm.latitude = String(lat);
23
      }
24
    }
25
  };
26
</script>