VUE中使用高德地图(原生UI)
先吐槽一下,本人的环境是基于vue3.0的项目,上一位参与项目的同事使用的事vue-amap,因工作需要,另外一位同事去了别的项目,所以这个万恶的项目由本人自己维护,就是再本周新增了需求,根据不用大区的用户进入到系统,显示不同的地图边界。 由也正因为于本人能力有限,未能基于vue-amap实现新增的需求,所以考虑使用原生UI功能,但因为引入原生UI与与原生UI冲突,总是报错,所以被本人放弃第三方组件方式,直接使用原生UI来进行开发。
遇到的问题(后面会详细解说)
- 自定义窗体问题;
- 窗体内部事件监听问题;
- 根据坐标获取Address问题;
- 获取省份行政区划代码问题;
- 行政区划添加图层展示问题;
问题内容解说前,先插入一点题外话,就是如何看API,高德地图功能很强大,据说什么样的地图都可以实现。
首先,高德地图有示例中心,有普通JS的示例,原生UI的示例,那我们要看的部分就是原生UI的示例+高德地图(WebJs API)
这里附上地址:
高德地图组件UI示例地址:https://lbs.amap.com/api/amap-ui/demos/amap-ui-districtexplorer/multi-load
高德地图JSAPI地址:https://lbs.amap.com/api/javascript-api/summary
下面针对遇到的问题开始进行详细解说,以代码为主。
本人所有功能的代码
main.js 中引入的高德地图插件(项目中是使用了vue-amap这个第三方插件的)
代码如下:
import VueAMap from 'vue-amap';
Vue.use(VueAMap);
VueAMap.initAMapApiLoader({
key: '申请开发Web版地图的Key,再高德地图官方网站进行申请',
plugin: ['AMap.Scale', 'AMap.OverView', 'AMap.Geolocation'],
v: '1.4.4',
uiVersion: '1.0.11' // UI版本号
});
包含地图所有功能的vue文件UIMap.vue
<template>
<div class="uimap">
<div id="uimap" class="amap-box"></div>
</div>
</template>
<script>
import vm from '@/libs/vm';
import { USER_MIXINS } from '@/libs/mixins';
import NoNet from '@/assets/images/no-net.png';
import HasNet from '@/assets/images/has-net.png';
import Normal from '@/assets/images/Normal.png';
import Middle from '@/assets/images/Middle.png';
import Interrupt from '@/assets/images/Interrupt.png';
import Unknown from '@/assets/images/Unknown.png';
import { AMapManager, lazyAMapApiLoaderInstance } from 'vue-amap';
import $ from 'jquery';
import { type } from 'os';
let amapManager = new AMapManager();
const loadPromise = lazyAMapApiLoaderInstance.load();
export default {
mixins: [USER_MIXINS],
data() {
let self = this;
return {
a_provincecode: [],
districtExplorer: {},
locationInfo: {},
simpleInfoWindow: null,
amapManager: amapManager,
map: null,
zoom: '',
center: [116.50436, 39.78634],
markers: [],
lng: 0,
lat: 0,
areaName: '',
dataCount: '' // 异常数据条数
};
},
async mounted() {
this.locationInfo = await this.getFactoryStatesAndAbnormalCount();
this.$nextTick(() => {
let aMark = this.markers.forEach(item => {
return item.position;
}); // 覆盖默认的dom结构
loadPromise.then(() => {
let _self = this;
var _simpleInfoWindow = {};
this.map = new AMap.Map('uimap', {
center: this.center,
resizeEnable: true
});
AMapUI.loadUI(
[
'misc/MarkerList',
'overlay/SimpleMarker',
'overlay/SimpleInfoWindow',
'geo/DistrictExplorer'
],
(MarkerList, SimpleMarker, SimpleInfoWindow, DistrictExplorer) => {
// 创建一个实例
_self.districtExplorer = new DistrictExplorer({
map: _self.map
});
// just some colors
var $ = MarkerList.utils.$;
// 展示所有标记
var markerList = new MarkerList({
map: this.map,
// 从数据中读取位置, 返回lngLat
getPosition: function(item) {
return item.position;
},
getInfoWindow: function(data, context, recycledInfoWindow) {
if (recycledInfoWindow) {
recycledInfoWindow.setInfoTitle(
`<strong class="infoTitle">${
data.extData.factoryName
}</strong>`
);
recycledInfoWindow.setInfoBody(
`<p class="infoWindow">所在大区:${
data.extData.areaName
}</p>
<p class="infoWindow">异常数据量:${
data.extData.abnormalNumber
}</p>
<p class="infoWindow"><span><a class="goDetail amap-ui-infowindow-close" id="goDetail">详情</a></span><span class="right"><a class="close amap-ui-infowindow-close">关闭</a></span></p>`
);
return recycledInfoWindow;
}
return new SimpleInfoWindow({
infoTitle: `<strong class="infoTitle">${
data.extData.factoryName
}</strong>`,
infoBody: `<p class="infoWindow">所在大区:${
data.extData.areaName
}</p>
<p class="infoWindow">异常数据量:${
data.extData.abnormalNumber
}</p><p class="infoWindow "></span><span><a class="goDetail amap-ui-infowindow-close" id="goDetail" >详情</a></span><span class="right"><a class="close amap-ui-infowindow-close">关闭</a></p>`,
offset: new AMap.Pixel(0, -37)
});
},
// 构造marker用的options对象, content和title支持模板,也可以是函数,返回marker实例,或者返回options对象
getMarker: function(data, context, recycledMarker) {
let state = data.extData.state;
return new SimpleMarker({
iconStyle:
state === 'Interrupt'
? Interrupt
: state === 'Middle'
? Middle
: state === 'Unknown'
? Unknown
: state === 'Normal'
? Normal
: Normal,
// iconStyle: iconStyle,
containerClassNames: 'my-marker'
});
},
// 需要监听的marker事件
markerEvents: ['click', 'mouseover', 'mouseout'],
// 需要监听的infoWindow事件
infoWindowEvents: ['click', 'mouseover', 'mouseout'],
selectedClassNames: 'selected',
autoSetFitView: true
});
markerList.render(this.markers);
// 监听选中改变
markerList.on('selectedChanged', function(event, info) {
this.simpleInfoWindow = event.target['_singleInfoWindow'];
if (this.simpleInfoWindow) {
// 详情按钮监听。。
this.simpleInfoWindow
.get$Container()
.on('click', '.goDetail', function(event) {
event.stopPropagation();
_self.$store.dispatch('setCurrType', 4);
_self.routeTo(info.selected.data.extData);
});
}
});
// 获取当前定位
AMap.plugin('AMap.Geolocation', function() {
var geolocation = new AMap.Geolocation({
enableHighAccuracy: true, // 是否使用高精度定位,默认:true
timeout: 10000, // 超过10秒后停止定位,默认:5s
buttonPosition: 'RB', // 定位按钮的停靠位置
zoomToAccuracy: false // 定位成功后是否自动调整地图视野到定位点
});
_self.map.addControl(geolocation);
geolocation.getCurrentPosition(function(status, result) {
if (status == 'complete') {
let infoWindow = new AMap.InfoWindow({
isCustom: true,
content: `<p class="self-position"><strong>${
result.formattedAddress
}</strong></p>`,
offset: new AMap.Pixel(0, -20)
});
infoWindow.open(_self.map, [
result.position.lng,
result.position.lat
]);
// onComplete(result);
} else {
_self.$Message.error(result);
}
});
});
// 获取省份编码(标记点所在的省份)
AMap.plugin('AMap.Geocoder', function() {
var geocoder = new AMap.Geocoder({
// city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycode
// city: '010'
});
_self.markers.forEach(item => {
let lnglat = item.extData.location;
geocoder.getAddress(lnglat, function(status, result) {
if (status === 'complete' && result.regeocode) {
var address = result.regeocode.addressComponent;
_self.$set(item.extData, 'adcode', address.adcode);
_self.$set(item.extData, 'citycode', address.citycode);
_self.$set(
item.extData,
'proecode',
item.extData.adcode.substring(0, 2) + '0000'
);
var formatAddress = result.regeocode.formattedAddress;
_self.a_provincecode.push(item.extData.proecode);
} else {
_self.$Message.error('根据经纬度查询地址失败!');
return false;
// log.error('根据经纬度查询地址失败');
}
});
});
});
// 多区域加载
// var adcodes = [370000, 330100, 330200, '0871'];
}
);
});
});
},
methods: {
async getFactoryStatesAndAbnormalCount() {
let { data } = await this.$http.get(
'/outlierquery/v1/outlier/factory/stateAndAbnormalCount',
{
params: {
orgLevel: this.orgLevel,
uri: this.uri
}
}
);
if (data.code !== 0) return;
if (data.result.length == 0) {
this.$Message.error('暂无水厂数据');
return;
}
this.markers = data.result.map((item, index) => {
// 0 离线 1 在线
const Icon =
item.state == '0' ? NoNet : item.state == '1' ? HasNet : '';
const POSITION = item.location.split(',');
let _this = this;
return {
extData: item,
position: POSITION,
icon: Icon,
visible: true,
draggable: false
};
});
let aLng = this.markers.map(item => {
return parseFloat(item.position[0]);
});
let aLat = this.markers.map(item => {
return parseFloat(item.position[1]);
});
let { maxLng, minLng, maxLat, minLat } = {
maxLng: Math.max(...aLng),
minLng: Math.min(...aLng),
maxLat: Math.max(...aLat),
minLat: Math.min(...aLat)
};
this.center = [(maxLng + minLng) / 2, (maxLat + minLat) / 2];
return { maxLng, minLng, maxLat, minLat };
},
routeTo(point) {
this.$router.push({
name: 'abnormal_data_count',
query: {
factoryUri: point.factoryUri,
factoryName: point.factoryName,
orgLevel: 5
}
});
},
renderAreaNode(areaNode) {
var colors = ['#dc3912'];
// 绘制子区域
this.districtExplorer.renderSubFeatures(areaNode, function(feature, i) {
var fillColor = colors[i % colors.length];
var strokeColor = colors[colors.length - 1 - (i % colors.length)];
return {
cursor: 'default',
// bubble: true,
// strokeColor: strokeColor, // 线颜色
// strokeOpacity: 0, // 线透明度
strokeWeight: 0.2 // 线宽
// fillColor: fillColor, // 填充色
// fillOpacity: 0.15 // 填充透明度
};
});
// 绘制父区域
this.districtExplorer.renderParentFeature(areaNode, {
zIndex: 12,
cursor: 'default',
bubble: true,
strokeColor: '#333', // 线颜色
strokeOpacity: 1, // 线透明度
strokeWeight: 0.2, // 线宽
fillColor: null, // 填充色
fillOpacity: 0.35 // 填充透明度
});
}
},
watch: {
map: function() {
if (this.map) {
this.map.setFitView([new AMap.Polyline({ path: this.markers })]);
}
},
a_provincecode: function() {
let _self = this;
if (
this.a_provincecode &&
this.districtExplorer &&
this.a_provincecode.length === this.markers.length
) {
this.districtExplorer.loadMultiAreaNodes(this.a_provincecode, function(
error,
areaNodes
) {
if (error) {
_self.$Message.error(error);
return false;
}
// 清除已有的绘制内容
_self.districtExplorer.clearFeaturePolygons();
for (var i = 0, len = areaNodes.length; i < len; i++) {
_self.renderAreaNode(areaNodes[i]);
}
// 更新地图视野
// _self.map.setFitView(districtExplorer.getAllFeaturePolygons());
});
}
}
}
};
</script>
<style lang="less">
#uimap {
min-height: 1260px;
}
.infoTitle {
padding: 0 10px;
height: 32px;
line-height: 32px;
}
.infoWindow {
min-width: 200px;
height: 32px;
line-height: 32px;
padding: 0 10px;
.right {
float: right;
}
}
.self-position {
background-color: #fff;
padding: 10px;
border: 1px solid #53aeef;
position: relative;
top: -5px;
}
</style>