地图在常规的vue项目中是一种比较常见的内容,通常我们只需要按照官方的文档示例以及api文档即可满足各种开发的需求,但是官方的文档示例通常都是直接在html文件中展现、js代码也是直接写在script中,然而vue式的开发却需要使用组件的形式,因此在结构上以及相关的方法与内容的定义上是有一定的区别的,因此这里记录vue组件式开发地图的一些常规操作。
引入高德地图
引入方式可以直接参照官方
同步加载:在index.html中加上标签引入,然后在对应的组件中即可使用AMap对象。如:
// 在index.html中放置
<script src="https://webapi.amap.com/maps?v=1.4.15&key=key值"></script>
异步加载:异步的加载方式与官方有点差异,但原理也是一样的。
第一步:建立一个AMap.js文件用于配置异步加载地图,内容为
export default function MapLoader() {
return new Promise((resolve, reject) => {
if (window.AMap) {
resolve(window.AMap);
} else {
let script = document.createElement("script");
script.type = "text/javascript";
script.async = true;
script.src = "http://webapi.amap.com/maps?v=1.4.15&callback=onAMapLoaded&key=key值";
script.onerror = reject;
document.head.appendChild(script);
}
window.onAMapLoaded = () => {
resolve(window.AMap);
};
});
}
第二步:将该文件导入main.js并且在vue原型链上注册该方法
// 挂载高德地图
import MapLoader from "src/utils/AMap.js";
Vue.prototype.$map = MapLoader;
第三步:在对应的.vue组件中使用,注意在mounted生命周期中创建并使用该方法
mounted() {
this.$map().then(AMap => {
let map = new AMap.Map("login-box", {
center: [117.000923, 36.675807]
});
});
}
通常情况下同步加载的第一次加载速度是比较慢的,因此如果项目中仅仅只有几个地方使用地图,建议使用异步加载,但如果项目中比较多的使用地图且项目带宽允许的情况下,可以使用同步加载。
补充:加载地图插件
插件的加载形式。
同步加载:直接在标签的src后面加上&plugin=xxx即可。如:
<script src="https://webapi.amap.com/maps?v=1.4.15&key=key值&plugin=AMap.ControlBar"></script>
然后在对应的组件中即可:new AMap.ControlBar()之类的
异步加载方式一:通过AMap.plugin()这个方法来加载,第一个参数为一个插件数组,第二个为回调函数。
this.$map().then(AMap => {
let map = new AMap.Map("login-box", {
center: [117.000923, 36.675807],
zoom: 11
});
AMap.plugin(['AMap.ControlBar'],() => {
let controlbar= new AMap.ControlBar();
map.addControl(controlbar);
});
});
异步加载方式二:在之前的AMap.js中的script.src连接后面直接使用&plugin=xxx即可,这种其实就是插件的同步加载方式,只是地图的异步加载的而已。
script.src = "http://webapi.amap.com/maps?v=1.4.15&callback=onAMapLoaded&key=key值&plugin=AMap.ControlBar";
使用:直接new即可
this.$map().then(AMap => {
let map = new AMap.Map("login-box", {
center: [117.000923, 36.675807],
zoom: 11
});
let controlbar= new AMap.ControlBar();
map.addControl(controlbar);
});
组件内的使用建议
vue组件形式的交互方式与原生js中的交互方式是有许多差异的。总结几点:
第一点:但凡使用new关键字创建出来的实例对象,建议在data中定义一个变量用于保存,如:
<template>
<div class="login-box" id="login-box"></div>
</template>
<script>
export default {
data() {
return {
map: {}, // 保存地图对象
toolbar: {} // 保存controlBar对象-这是一个地图插件
};
},
methods: {},
mounted() {
this.map = new AMap.Map("login-box", {
center: [117.000923, 36.675807],
zoom: 11
});
this.toolbar = new AMap.ControlBar();
this.map.addControl(this.toolbar);
}
};
</script>
这样的好处就是本组件内都可以直接通过this来获取到需要的实例内容,方便做操作
第二点:但凡需要同时创建多个实例对象的内容,建议在data中创建一个数组保存,并且定义一个识别数组,在push实例对象的时候同时push一个唯一识别内容进去,方便后续从实例对象数组中寻找。
代码示例:
<template>
<div class="login-box" id="login-box"></div>
</template>
<script>
export default {
data() {
return {
map: {},
markers: [], // 保存多个点标记的内容的数组
markersData: [] // 保存点标记对应的唯一标记,用于寻找点标记
};
},
methods: {
// 当页面执行了某个操作的时候,触发了clickMarker。需要达到效果如:让该标号对应的点标记亮起来
clickMarker(row){
// row是某个操作后列表的详情值,里面有单个内容的id
// 找出这个id在markersData中的标号。
let index = this.markersData.findIndex(item => {
return row.id == item;
});
// 这个就是该id对应起来的点标记,然后就可以操作了。-原因是markers和markersData中的下标是一一对应的
this.markers[index].setIcon('xxx');
}
},
mounted() {
this.map = new AMap.Map("login-box", {
center: [117.000923, 36.675807],
zoom: 11
});
// 通过接口获取到一个数据列表后,需要将其上的内容都标记在地图上。
/* 数据格式:
[
{id: '1',lng: 128.15643,lat: 165.45632},
{id: '2',lng: 128.15643,lat: 165.45632},
{id: '3',lng: 128.15643,lat: 165.45632}
]
*/
getList().then(res => {
if (res) {
for (let i = 0; i < res.length; i++) {
// 每次循环创建一个点标记
let marker = new AMap.Marker({});
// 设置内容后将点标记渲染到地图上
marker.setPisition([res.lng, res.lat]);
this.map.add(marker);
// 保存点标记
this.markers.push(marker);
// 保存点标记唯一标号-作用在后面
this.markersData.push(res.id);
}
}
});
}
};
</script>
第三点:建议将地图要素的要素创建过程都独立封装成方法,这样可以让组件结构内容变得更加的清晰。
<template>
<div class="login-box" id="login-box"></div>
</template>
<script>
export default {
data() {
return {
map: {},
markers: [] // 保存多个点标记的内容的数组
};
},
methods: {
// 创建地图
createMap() {
this.map = new AMap.map('xx',{
center: [117.000923, 36.675807],
zoom: 11
//......
});
},
// 创建点标记
createMarker(arr){
let marker = new AMap.marker({
icon: arr.icon,
position: [arr.lng,arr.lat]
//......
});
marker.on('click',()=>{
// xxxxx
})
return marker;
},
// 清除地图上的所有内容
clearMap() {
this.map.clearMap();
},
},
mounted() {
this.createMap();
this.markers.push(this.createMarker(arr));
}
};
</script>
参照高德地图的示例以及api足以完成地图相关的开发内容,项目示例与vue之间的转换本质是一样的,区别仅仅只是形式不同而已。
vue[高德地图自定义InfoWindow弹出框中事件问题]