需求:实现点击获取经纬度、定位、对特殊位置标点及自定义信息窗体功能。
高德地图的官网API:概述-地图 JS API 1.4 | 高德地图API
vue-amap的中文文档:组件 | vue-amap
实现:
1、安装vue-amap插件
npm install vue-amap --save
2、项目引入
在main.js中引入
需要提前申请高德key,步骤附在最后了
// 高德地图配置
import VueAMap from 'vue-amap' // 引入插件
Vue.use(VueAMap) // 使用插件
VueAMap.initAMapApiLoader({ // 初始化插件key: '高德申请的key', // 高德keyplugin: ['AMap.Geocoder', 'AMap.PlaceSearch', 'AMap.Geolocation', 'AMap.CitySearch'], // 插件集合,根据自己的需求添加uiVersion: '1.0.11', // 不加会报错,加上吧v: '1.4.15' // 默认高德 sdk 版本为 1.4.4
})
// 申请的Web端(JS API)的需要写上下面这段话
window._AMapSecurityConfig = {securityJsCode: '高德申请的kedy对应的安全密钥' // 高德Web端安全密钥
}
3、新建一个Map.vue文件
这里直接放我封装的组件
<template><div class="Map"><!-- 地图组件 --><el-amapvid="amapContainer"class="amapClass":zoom="zoom":plugin="plugin":center="center":events="events"><!-- 这里用于点击时的标点 --><el-amap-markerv-for="(marker, index) in markers":key="index + '1'":position="marker"/><!-- 这里用于特殊位置的标点 --><el-amap-markerv-for="(marker, index) in markerList":key="index + '2'":position="marker.lnglats":icon="getIcon(marker)":events="marker.events":offset="[-24, -24]"/><!-- 信息窗体 --><el-amap-info-windowv-if="currentWindow.visible":position="currentWindow.position":visible.sync="currentWindow.visible":content="currentWindow.content":close-when-click-map="false":events="currentWindow.events":offset="[0, -24]"/></el-amap></div>
</template><script>import LED0 from '@/assets/imgs/LED-0.png'
import LED1 from '@/assets/imgs/LED-1.png'
import lamppost0 from '@/assets/imgs/lamppost-0.png'
import lamppost1 from '@/assets/imgs/lamppost-1.png'
import tourGuide0 from '@/assets/imgs/tourGuide-0.png'
import tourGuide1 from '@/assets/imgs/tourGuide-1.png'
export default {name: 'Map',props: {zoom: { // 地图缩放比例。zoom值越小,越宏观、越大,越微观。type: Number,default: 14},center: {type: Array,default: () => [120.147076, 30.245426] // 西湖风景区的经纬度},markers: {type: Array,default: () => []},markerList: {type: Array,default: () => []},currentWindow: {type: Object,default: () => ({position: [],visible: false,content: '测试'})}},data() {const self = thisreturn {LED0,LED1,lamppost0,lamppost1,tourGuide0,tourGuide1,address: null,loaded: false,events: {init(o) {console.log('地图初始化', o)// ... 初始地图的一些操作},complete(){// ... 地图渲染完成后的一些操作}// 点击地图click: self.click},// 一些工具插件plugin: [{pName: 'Geocoder',events: {init(o) {console.log('Geocoder', o.getAddress())}}},{// 定位pName: 'Geolocation',events: {init(o) {// o是高德地图定位插件实例o.getCurrentPosition((status, result) => {// 会存在失败的时候,官网回答:https://lbs.amap.com/faq/js-api/map-js-api/position-related/43361/console.log('查询成功定位信息', status, result)if (result && result.position) {// 根据经纬度设置坐标 --不想替换掉默认的center的可以先注释self.$emit('update:center', [result.position.lng, result.position.lat])// self.$emit('update:markers', [[result.position.lng, result.position.lat]])// loadself.loaded = true// 页面渲染好后self.$nextTick()}})}}},{// 搜索 --我这里没用到pName: 'PlaceSearch',events: {init(instance) {console.log('搜索', instance)}}},{// 定位城市pName: 'CitySearch',events: {init(o) {// o是高德地图定位插件实例o.getLocalCity(function(status, result) {if (status === 'complete' && result.info === 'OK') {// 查询成功,result即为当前所在城市信息console.log('查询成功,当前所在城市信息', result)}})}}}]}},methods: {// 点击地图获取经纬度和具体位置click(e) {const { lng, lat } = e.lnglatthis.$emit('update:center', [lng, lat])this.$emit('update:markers', [[lng, lat]])console.log('[lng, lat]', [lng, lat])// 这里通过高德 SDK 完成。获取具体地址的const geocoder = new AMap.Geocoder({radius: 1000,extensions: 'all'})const that = thisgeocoder.getAddress([lng, lat], function(status, result) {if (status === 'complete' && result.info === 'OK') {if (result && result.regeocode) {that.address = result.regeocode.formattedAddressconsole.log('具体位置:', result.regeocode.formattedAddress)that.$nextTick()}}that.$emit('getLocation', { lng, lat, address: that.address })})},getIcon(item) {if (item.mediaTypeName === '灯杆屏') {return item.status ? this.lamppost0 : this.lamppost1} else if (item.mediaTypeName === '导览屏') {return item.status ? this.tourGuide0 : this.tourGuide1} else return item.status ? this.LED0 : this.LED1}}
}
</script>
<style lang="scss" scoped>
/* 指定地图的宽高 */
.amapClass, .Map {width: 100%;height: 100%;
}
</style>
关于el-amap-marker的属性:
1、position:为marker点的坐标(经纬度),接收数组
3、events:事件集合对象,click、dblclick、rightclick、mouseover、mouseout等
events: {click: (e) => {// ...点击操作},dblclick: (e) => {// ...双击操作},...
}
4、offset:偏移量
其他我没用到的还有:
5、clickable:true允许用户可点击marker点(默认也是true)
6、animation:marker点的动画效果
marker点弹跳效果:设置值为 AMAP_ANIMATION_BOUNCE
7、label:点显示的简略信息
8、content可以是文字字符串也可以是html
关于el-amap-info-window信息窗体的属性
静态属性
名称 | 类型 | 说明 |
---|---|---|
vid | String | 组件的ID。 |
isCustom | Boolean | 是否自定义窗体。设为true时,信息窗体外框及内容完全按照content所设的值添加(默认为false,即在系统默认的信息窗体外框中显示content内容) |
autoMove | Boolean | 是否自动调整窗体到视野内(当信息窗体超出视野范围时,通过该属性设置是否自动平移地图,使信息窗体完全显示) |
closeWhenClickMap | Boolean | 控制是否在鼠标点击地图后关闭信息窗体,默认false,鼠标点击地图后不关闭信息窗体 |
showShadow | Boolean | Boolean 控制是否显示信息窗体阴影,取值false时不显示窗体阴影,取值true时显示窗体阴影默认值:false |
offset | Array | 相对于基点的偏移量。默认情况是信息窗体的底部中心点(BOTTOM_CENTER) 和基点之间的偏移量 |
动态属性
名称 | 类型 | 说明 |
---|---|---|
content | String/HTML | 显示内容。支持字符串和HTML。 |
template | String | 支持传入 Vue 模板。v0.4.0 开始支持。 |
vnode | VNode 或 Funtion: (Instance) => VNode | 支持 VNode 渲染。v0.4.2 开始支持 |
contentRender | Function: (createElement: () => VNode, instance) => VNode | 支持 VNode render 渲染。v0.4.3 开始支持 |
size | Size | 信息窗体尺寸(isCustom为true时,该属性无效) |
position | Array | 信息窗体显示基点位置(自v1.2 新增) |
visible | Boolean | 信息窗体是否显示。这里需要注意的是,高德地图只支持同时一个信息窗体的显示。所以一旦有窗体显示切换的场景,visible数组的状态需要自行维护。 |
ref 可用方法
提供无副作用的同步帮助方法
函数 | 返回 | 说明 |
---|---|---|
$$getInstance() | AMap.InfoWindow | 获取infoWindow 实例 |
事件(也是events里的)
事件 | 参数 | 说明 |
---|---|---|
init | Object | 高德组件实例 |
change | 属性发生变化时 | |
open | 信息窗体打开之后触发事件 | |
close | 信息窗体关闭之后触发事件 |
4、使用地图组件
我把使用的页面也全贴上了,但其实search-box里面的东西大家可以忽略,只是针对markerList的查询过滤
<template><div class="box"><div class="search-box"><el-form ref="queryForm" label-width="auto" class="searchForm" :model="searchForm" style="padding: 16px 0 0;"><el-form-item label="类型" prop="mediaType"><el-select v-model="searchForm.mediaType"><el-option v-for="item in digitalTypeOptions" :key="item.value" :label="item.label" :value="item.value" /></el-select></el-form-item><el-form-item label="区域" prop="region"><el-select v-model="searchForm.region" clearable><el-option v-for="item in regionOptions" :key="item.value" :label="item.label" :value="item.value" /></el-select></el-form-item><el-form-item label-width="20px"><el-button v-permission="['ResourceDistribution:query']" class="search-btn" icon="el-icon-search" type="primary" @click="getDetail">查询</el-button><el-button class="reset-btn" icon="el-icon-refresh-left" @click="resetForm('queryForm')">重置</el-button></el-form-item><el-form-item label="设备名称" prop=""><el-select v-model="searchKey" filterable clearable placeholder="请输入关键字" @change="quickOrientation"><el-option v-for="item in markerList" :key="item.mediaCode" :label="item.mediaName" :value="item.mediaCode" /></el-select><!-- <el-input id="search" v-model="searchKey" placeholder="请输入设备名称" /> --></el-form-item><el-form-item label-width="20px" style="width: 100px;"><el-button v-permission="['ResourceDistribution:query']" class="search-btn" type="primary" @click="quickOrientation">快速定位</el-button></el-form-item></el-form><div class="rightType"><div v-for="item in digitalTypeOptions" :key="item.value" class="iconItem"><svg-icon v-if="item.label === '灯杆屏'" icon-class="lamppost" /><svg-icon v-else-if="item.label === '导览屏'" icon-class="tourGuide" /><svg-icon v-else icon-class="LED" /><span>{{ item.label }}</span></div></div></div><div class="rightBottom"><span class="successStatus">已启用</span><span class="errorStatus">已禁用</span></div><!-- 地图组件 --><Map:center.sync="center":markers.sync="markers":zoom.sync="zoom":marker-list="markerList":current-window="currentWindow"@getLocation="getLocation"/></div>
</template><script>
import Map from '@/components/Map'
import { dictList, deviceFilter } from '@/api/resource'
export default {name: 'GaodeDituAmap',components: { Map },data() {return {searchForm: {mediaType: '',region: ''},searchKey: '',digitalTypeOptions: [],regionOptions: [],currentWindow: {position: [],visible: false,content: '',events: {}},markerList: [],markers: [],center: [121.133858, 30.606042],zoom: 14 // 地图缩放比例。zoom值越小,越宏观、越大,越微观。}},mounted() {this.getDict()this.getDetail()},methods: {// 获取标点信息async getDetail() {this.currentWindow.visible = falseconst that = thisconst { data } = await deviceFilter(this.searchForm)data.forEach(item => {item.lnglats = [item.longitude, item.latitude]item.events = {click(e) {console.log('点击标点', e)that.center = item.lnglatsthat.currentWindow.content = that.createWinContent(item)that.currentWindow.position = item.lnglatsthat.currentWindow.events = {close(e) {console.log('窗体关闭', e)that.currentWindow.visible = false}}that.currentWindow.visible = true}}})this.markerList = data},/*** 基础配置信息*/async getDict() {const { data: { area, digitalType }} = await dictList('dictNames=area&dictNames=digitalType')this.regionOptions = areathis.digitalTypeOptions = digitalType},// 重置resetForm(formName) {this.$refs[formName].resetFields()this.zoom = this.$options.data.call(this).zoomthis.getDetail()},// 快速定位quickOrientation() {if (!this.searchKey) {this.markers = []this.currentWindow.visible = falsereturn}const cur = this.markerList.find(f => f.mediaCode === this.searchKey)if (cur) {this.center = [cur.longitude, cur.latitude]// this.markers = [this.center]this.currentWindow.content = this.createWinContent(cur)this.currentWindow.position = [cur.longitude, cur.latitude]this.currentWindow.visible = truethis.zoom = 15}},// 获取经纬度及地理位置getLocation({ lng, lat, address }) {console.log('获取到经纬度和地址啦:', lng, lat, address)},// 画信息窗createWinContent(item) {return `<div><div style="display: flex;margin-bottom: 12px">${item.src ? `<img src="${item.src}" style="width: 120px;margin-right: 16px;">` : ''}<div style="display: flex;flex-direction: column;justify-content: space-around;"><strong style="font-size: 18px">${item.mediaName}</strong><div style="margin-top: 6px"><span style="font-size: 14px;color: #0082FF;padding: 0px 6px;background: rgba(0,130,255,0.15);border-radius: 4px;">${item.mediaTypeName}</span><span style="font-size: 14px;color: ${!item.status ? '#46A77B' : '#E30000'};padding: 0px 6px;background: ${!item.status ? '#46A77B26' : '#E3000026'};border-radius: 4px;">${!item.status ? '已启用' : '已禁用'}</span></div><div style="margin-top: 8px"><i class="el-icon-location" style="color: #0082FF"></i><span style="font-size: 14px;">${item.regionName}</span></div></div></div><div style="font-size: 14px;color: #666666;line-height: 20px;"><span>${item.specification},</span><span>${item.supplier},</span><span>${item.supplierContact},</span><span>${item.supplierPhone}</span></div></div>`}}
}
</script>
<style lang="scss" scoped>
.box {width: 100%;height: 100%;box-sizing: border-box;padding: 0px;position: relative;.search-box {position: absolute;background-color: #FFFFFF;width: calc(100% - 32px);top: 16px;left: 16px;z-index: 999;border-radius: 4px;.searchForm .el-form-item {margin: 0 0px 16px;}.tip-box {width: 100%;max-height: 260px;position: absolute;top: 30px;overflow-y: auto;background-color: #fff;}.rightType{position: absolute;right: 0px;bottom: -24px;transform: translateY(100%);z-index: 999;background: #FFFFFF;border-radius: 4px;padding: 16px;display: flex;align-items: center;flex-direction: column;.iconItem{font-size: 14px;color: #4A4A4A;display: flex;align-items: center;flex-direction: column;.svg-icon{width: 24px;height: 24px;}}.iconItem+.iconItem{margin-top: 24px;}}}.rightBottom{position: absolute;right: 16px;bottom: 16px;z-index: 999;padding: 16px;font-size: 14px;color: #4A4A4A;background-color: #FFFFFF;border-radius: 4px;.successStatus{margin-right: 24px;}.successStatus::before{content: '';display: inline-block;height: 8px;width: 8px;background-color: #46A77B;border-radius: 50%;margin-right: 5px;}.errorStatus::before{content: '';display: inline-block;height: 8px;width: 8px;background-color: #FF4747;border-radius: 50%;margin-right: 5px;}}
}/* 指定地图的宽高 */
.amapClass {width: 100%;height: 100%;
}
</style>
成果大致样式如下:
附:高德Key申请
登录后到这个地址:我的应用 | 高德控制台
1、点击添加key
2、根据自己的需求选择服务平台,可以看看对应的“可使用服务” 来决定,我这里选择Web端
3、提交后就有一条新增的记录,复制放进代码使用就好啦
参考地址:
vue-amap基于vue的高德地图使用_amap vue-CSDN博客
1.5.1 信息窗体 - vue-amap 中文文档 - 开发文档 - 文江博客