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> |