天天看點

vue3部署高德地圖js api,如何将高德地圖infoWindow互動事件挂載到vue執行個體上

首先要想使用高德地圖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上,我試了一下,但是有報錯,是以棄用了。換了個思路,使用這種方法來實作,雖然這樣會輕微的污染全局方法,但是确實能夠很完美的解決問題。