首先要想使用高德地圖js api,需要先在高德開放平台注冊成為開發者,注冊後,可以建立一個應用,擷取你應用的key。
獲得Key之後,我們就可以需要在項目中添加JS API 的入口腳本标簽,這裡我選擇添加到public/index.html中:
<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=您申請的key值"></script>
添加之後,你就可以在你的元件中使用啦。
<template>
<div class="map-container">
<!-- 地圖執行個體 -->
<div id="mapContainer" class="map-content"></div>
<!-- 地圖控件(放大縮小控件) -->
<div v-if="zoomControl" class="zoom-control">
<div class="control-item" @click="mapZoom(0)">+</div>
<div class="control-item" @click="mapZoom(1)">-</div>
</div>
<!-- 定位控件 -->
<div v-if="locationControl" class="location-control">
<div class="control-item" @click="getLocation">
<i class="iconfont icon-dingwei"></i>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue';
export default {
props: {
zoomControl: {
type: Boolean,
default: true
},
locationControl: {
type: Boolean,
default: true
},
locationPoint: {
type: Array,
default: () => []
},
caseData: {
type: Array,
default: () => []
},
selectText: {
type: String,
default: "選擇"
}
},
data(){
return {
mapContent: "",
location: {
address: "",
point: []
},
points:[],
locationMarker: "",
markers: [],
}
},
mounted(){
this.initMapContorl();
},
methods: {
// 初始化地圖執行個體
initMapContorl(){
this.mapContent = new AMap.Map('mapContainer', {
zoom:11, //級别
center: [117.184811,34.261792], //中心點坐标
resizeEnable: true
});
if(this.locationPoint.length>0){
this.location.point = [this.locationPoint.long,this.locationPoint.lat];
this.setMarkerInMap(this.location.point,0);
}
if(this.caseData.length>0){
this.setMarkerInMap(this.caseData,1);
this.mapContent.setFitView();
}
},
// 地圖放大縮小的控件
mapZoom(type){
if(!this.mapContent) return false;
if(type){ // 縮小
this.mapContent.zoomOut();
}else{ // 放大
this.mapContent.zoomIn();
}
},
// 擷取定位資訊,這裡我使用的是html5提供的擷取位置資訊的方法。
getLocation(){
this.$store.dispatch('getGPSLocation').then((res) => {
this.location.point = [res.long,res.lat];
this.setMarkerInMap(this.location.point,0);
}).catch((error) => {
this.$toast({
show: true,
text: error?error:'擷取位置資訊失敗。'
})
})
},
// 設定marker到地圖中,可以設定一個或者多個
setMarkerInMap(points,type){
if(type==0){
this.locationMarker = new AMap.Marker({
icon: new AMap.Icon({
image: "//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
size: new AMap.Size(30, 40),
imageSize: new AMap.Size(30, 40),// 圖示所用圖檔大小
}),
position: points
});
this.locationMarker.setMap(this.mapContent);
}else{
this.points = points.map(item => {
let marker = new AMap.Marker({
icon: new AMap.Icon({
image: "//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
size: new AMap.Size(30, 40),
imageSize: new AMap.Size(30, 40),// 圖示所用圖檔大小
}),
position: [item.long,item.lat]
});
marker.setMap(this.mapContent);
this.creatInfoWindow(item,marker);
this.markers.push(marker);
return [item.long,item.lat];
});
}
},
// 建立infoWindow,添加互動
creatInfoWindow(item, marker){
let infoWindow = new AMap.InfoWindow({
isCustom: false, //使用自定義窗體
position: [item.long,item.lat],
content: `<div>
<div style="color: var(--theme); font-size: 18px; margin-bottom: 5px;">書櫃</div>
<div style="font-size: 14px;">
<div style="margin-bottom: 5px;">${item.eqName}</div>
<div style="margin-bottom: 5px;">
<i class="iconfont icon-map" style="font-size: 18px;"></i>
<label>${item.address}</label>
</div>
<div style="display: flex;align-items: center;justify-content: space-between;">
<label>距離:${item.distance}</label>
<button style="border: 0; outline: none; padding: 8px 15px; background-color: var(--theme); color: #fff; border-radius: 4px;" onClick="mapCaseSelect(${item.eqId});">${this.selectText}</button>
</div>
</div>
</div>`,
offset: new AMap.Pixel(5, -40)
});
// 因為添加到infowindow中的button綁定的是window的全局方法,是以這裡需要将元件的局部方法指派給全局方法。
if(!window.mapCaseSelect){
window.mapCaseSelect = this.mapCaseSelect;
}
// 點選marker打開infoWindow
AMap.event.addListener(marker, 'click', () => {
infoWindow.open(this.mapContent, marker.getPosition());
});
},
mapCaseSelect(eqId){
let itemEq = this.caseData.find(item => item.eqId==eqId);
this.$emit('selectChange',itemEq);
}
}
}
</script>
<style >
.map-container{
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-content: space-between;
align-items: center;
position: relative;
.map-content{
width: 100%;
flex: 1;
}
.zoom-control{
position: absolute;
top: 10px;
left: 10px;
background-color: #ffffff;
border-radius: 6px;
box-shadow: 0px 0px 6px #e2e2e2;
.control-item{
width: 40px;
height: 40px;
text-align: center;
line-height: 40px;
font-size: 24px;
columns: #333333;
cursor: pointer;
position: relative;
&:active{
background-color: #e2e2e2;
}
}
}
.location-control{
position: absolute;
top: 100px;
left: 10px;
width: 40px;
height: 40px;
overflow: hidden;
background-color: #ffffff;
border-radius: 50%;
box-shadow: 0px 0px 6px #e2e2e2;
.control-item{
width: 40px;
height: 40px;
text-align: center;
line-height: 40px;
font-size: 24px;
columns: #333333;
cursor: pointer;
position: relative;
&:active{
background-color: #e2e2e2;
}
}
}
}
</style>
這裡的一個難點就是動态添加的infoWindow中的事件無法在元件中監聽到,網上查找了一下,都是使用vue.extend()生成html添加到infowindow上,我試了一下,但是有報錯,是以棄用了。換了個思路,使用這種方法來實作,雖然這樣會輕微的污染全局方法,但是确實能夠很完美的解決問題。