最近的一个项目中需要用到地图功能,经过一番调研,决定对于国内用户采用高德地图API,对于国外用户采用谷歌地图API。本期讲讲如何在vue项目中封装高德地图组件,下一期讲述如何封装谷歌地图组件。
本次组件所满足的大致需求是:
到高德开放平台注册一个开发者账号,登录后创建key。具体操作可以参考该连接:https://lbs.amap.com/api/javascript-api-v2/prerequisites
1. Yarn/NPM 安装 Loader
yarn add @amap/amap-jsapi-loader
或者 npm i @amap/amap-jsapi-loader --save
2. 新建 CustomAmap.vue 文件
在项目中新建 CustomAmap.vue
文件,用作地图组件
3. 创建地图容器 4. 设置地图容器样式 5. 引入JS API Loader 6. 初始化map对象 7. 创建地图 生产环境中: 开发环境中: 地图初始化函数 至此,一个基本的地图组件就成型了。 8. 功能1:传入经纬度数据,转换为一个标记点显示在地图上 9. 功能2:鼠标点击地图组件将产生一个新的标记点,并且地图上只保留一个最新的标记点 10. 功能3:提供一个输入框,可模糊搜索地点
在CustomAmap.vue
地图组件中创建id
属性为container
<template>
<div class="plug-custom-amap" :style="cssVars">
<div class="map-container" id="container">div>
div>
template>
我通过变量的方式来控制地图的高度,这样就可以在父组件传递属性值来控制地图的高度了。
在地图组件 CustomAmap.vue
中引入 amap-jsapi-loader
import AMapLoader from '@amap/amap-jsapi-loader'
注意:声明map对象时,在vue2和vue3中是有区别的,本项目用的是vue2。在vue2中使用,在 data 函数中不声明map
对象,可以直接使用this.map
赋值或者采用非响应式的普通对象来存储。
在created
钩子函数中使用安全密钥(申请的时候会有一个key和一个安全密钥,注意区分),官方介绍了两种使用方式,一种是通过代理服务器转发(安全,推荐在生产环境中使用),一种是明文方式设置(不安全,推荐在开发环境中使用)。
根据高德地图开发的建议,自定义一个代理服务器。https://lbs.amap.com/api/jsapi-v2/guide/abc/preparecreated() {
window._AMapSecurityConfig = {
serviceHost: '代理服务器域名或地址/_AMapService'
}
}
created() {
window._AMapSecurityConfig = {
securityJsCode:'「申请的安全密钥」'
}
}
initMap
mounted() {
this.initMap()
}
/* 初始化地图实例 */
methods:{
initMap() {
AMapLoader.load({
key: '申请的key', // 申请好的Web端开发者Key,首次调用 load 时必填
version:"2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins:['AMap.Scale', 'AMap.ToolBar'], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
}).then((AMap)=>{
this.map = new AMap.Map("container",{ // 设置地图容器id
viewMode:"3D", // 是否为3D地图模式
zoom: 11, // 初始化地图级别
resizeEnable: true
})
const scale = new AMap.Scale()
const toolBar = new AMap.ToolBar()
this.map.addControl(scale) // 添加比例尺
this.map.addControl(toolBar) // 添加简单的缩放按钮
}).catch(e=>{
console.log(e)
})
}
}
/* 初始化标记点 */
initMarker() {
const marker = new AMap.Marker({
icon: "//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
position: [this.longitude, this.latitude]
offset: new AMap.Pixel(-13, -30)
})
marker.setMap(this.map) // 将标记点放置到地图实例上
this.map.setCenter([this.longitude, this.latitude], true) // 设置地图中心点
}
/* 初始化左键添加标记事件 */
initAddMarker() {
this.map.on('click', (e) => {
this.map.clearMap() // 清理地图上的标记点
const longitude = e.lnglat.getLng()
const latitude = e.lnglat.getLat()
const marker = new AMap.Marker({
icon: "//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
position: [longitude, latitude],
offset: new AMap.Pixel(-13, -30)
})
marker.setMap(this.map) // 设置最新的标记点
this.newMarker = [longitude, latitude] // 将最新标记点保存一下,用于点击确定后,传递给父组件
})
},
<template>
<div class="plug-custom-amap" :style="cssVars">
<div class="map-container" id="container">div>
<div class="select-container">
<input class="pac-input" id="pacInput" ref="pacInput" type="text" placeholder="请输入关键字" />
<v-btn class="ml-2" small depressed @click="clear">清除v-btn>
div>
div>
template>
/* 搜索框:输入提示后查询 */
initSearchPlace() {
const autoOptions = { input: 'pacInput' }
const autoComplete = new AMap.AutoComplete(autoOptions)
const placeSearch = new AMap.PlaceSearch({ map: this.map }) // 构造地点查询类
autoComplete.on("select", function (e) {
placeSearch.setCity(e.poi.adcode)
placeSearch.search(e.poi.name) //关键字查询
}) // 注册监听,当选中某条记录时会触发
}
贴上完整代码(仅供参考)
<template>
<div class="plug-custom-amap" :style="cssVars">
<div class="map-container" id="container">div>
<div class="select-container" v-if="placeSearchAble">
<input class="pac-input" id="pacInput" ref="pacInput" type="text" placeholder="请输入关键字" />
<v-btn class="ml-2" small depressed @click="clear">清除v-btn>
div>
div>
template>
<script>
import AMapLoader from '@amap/amap-jsapi-loader'
export default {
name: "PlugCustomAmap",
props: {
height: { // 地图高度
type: String,
default: '500px'
},
placeSearchAble: { // 地点搜索框
type: Boolean,
default: false
},
addMarkerAble: { // 允许标记
type: Boolean,
default: false
},
zoom: { // 地图缩放级别
type: Number,
default: 11
},
latitude: { // 纬度
type: Number,
default: 0
},
longitude: { // 经度
type: Number,
default: 0
}
},
data() {
return {
newMarker: [this.longitude, this.latitude] // 新标记点
}
},
computed: {
cssVars() {
return {
'--mapHeight': this.height // 地图高度
}
},
/* 高德地图的key */
mapKey() {
return 'xxxxx' // 我的项目中在首次加载时调用接口获取的地图的key,然后存入了vuex,然后在这调用
}
},
created() {
window._AMapSecurityConfig = {
serviceHost: '代理服务器域名或地址/_AMapService'
}
},
mounted() {
this.initMap()
},
beforeDestroy() {
this.map.destroy()
this.map = null
},
methods:{
/* 初始化标记点 */
initMarker() {
const marker = new AMap.Marker({
icon: "//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
position: [this.longitude, this.latitude],
offset: new AMap.Pixel(-13, -30)
})
marker.setMap(this.map) // 将标记点放置到地图实例上
this.map.setCenter([this.longitude, this.latitude], true) // 设置地图中心点
},
/* 初始化左键添加标记事件 */
initAddMarker() {
this.map.on('click', (e) => {
this.map.clearMap() // 清理地图上的标记点
const longitude = e.lnglat.getLng()
const latitude = e.lnglat.getLat()
const marker = new AMap.Marker({
icon: "//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
position: [longitude, latitude],
offset: new AMap.Pixel(-13, -30)
})
marker.setMap(this.map) // 设置最新的标记点
this.newMarker = [longitude, latitude] // 将最新标记点保存一下,用于点击确定后,传递给父组件
})
},
/* 搜索框:输入提示后查询 */
initSearchPlace() {
const autoOptions = { input: 'pacInput' }
const autoComplete = new AMap.AutoComplete(autoOptions)
const placeSearch = new AMap.PlaceSearch({ map: this.map }) // 构造地点查询类
autoComplete.on("select", function (e) {
placeSearch.setCity(e.poi.adcode)
placeSearch.search(e.poi.name) //关键字查询
}) // 注册监听,当选中某条记录时会触发
},
/* 初始化地图实例 */
initMap() {
AMapLoader.load({
key:this.mapKey, // 申请好的Web端开发者Key,首次调用 load 时必填
version:"2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins:['AMap.Scale', 'AMap.AutoComplete', 'AMap.PlaceSearch', 'AMap.ToolBar'], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
}).then((AMap)=>{
this.map = new AMap.Map("container",{ //设置地图容器id
viewMode:"3D", //是否为3D地图模式
zoom: this.zoom, //初始化地图级别
resizeEnable: true
})
const scale = new AMap.Scale()
const toolBar = new AMap.ToolBar()
this.map.addControl(scale) // 添加比例尺
this.map.addControl(toolBar) // 添加简单的缩放按钮
this.placeSearchAble && this.initSearchPlace() // 如果placeSearchAble为true,则初始化搜索框功能
this.addMarkerAble && this.initAddMarker() // 如果addMarkerAble为true,则初始化左键添加标记功能
const initMarkerAble = this.latitude > 0 && this.longitude > 0
initMarkerAble && this.initMarker() // 如果props中的longitude、latitude属性有值,则初始化标记点
}).catch(e=>{
console.log(e)
})
},
/* 点击确认按钮,将标记点的经纬度值传递给父组件 */
confirm() {
const longitude = this.newMarker[0]
const latitude = this.newMarker[1]
this.$emit('setLongitudeLatitude', { longitude, latitude })
},
/* 清除地图上的标记 */
clear() {
this.map && this.map.clearMap() // 清空标记
this.$refs.pacInput.value = '' // 将输入框的关键字清空
this.newMarker = [0, 0]
}
}
}
script>
<style lang="less" scoped>
.plug-custom-amap {
position: relative;
.map-container {
padding:0;
margin: 0;
width: 100%;
height: var(--mapHeight);
}
.select-container {
position: absolute;
top: 5px;
left: 10px;
background: #fff none repeat scroll 0 0;
border: 1px solid #ccc;
margin: 10px auto;
padding: 6px;
font-size: 14px;
.pac-input {
border: 1px solid #ccc;
width: 350px;
padding-left: 5px;
}
}
/deep/ .amap-icon img {
width: 25px;
height: 34px;
}
/deep/ .amap-menu-outer {
padding-left: 0 !important;
}
}
style>