Vue中使用高德地图的学习记录
废话不多说,直接开始参考: https://blog.csdn.net/qq_39512863/article/details/90483781
·
前言
- 如果没有了解过高德地图,请勿看这篇文章,因为我不是从头说起的(2020-07-13)
安装引入
- 使用高德地图组件前,先在index.html中加入以下代码
<script type="text/javascript"
src="https://webapi.amap.com/maps?v=1.4.15&key=4365df5e295713cc4d8dcbdcef934a0f"></script>
<script src="https://webapi.amap.com/ui/1.0/main.js" type="text/javascript"></script>
功能使用
为某个区域添加遮罩(即只显示某个区域的地图)
// data里定义地图实例
data() {
return {
amapInstance:{},
...
}
}
methods: {
// 地图初始化就不贴了
...
// 为地图加载遮罩,只显示默认区域
mapLoadMask() {
// 这里一定要捕获this赋值给一个变量,不然在回调函数中调用this不是你想要的this
const _this = this
// https://lbs.amap.com/api/javascript-api/reference/search
// https://lbs.amap.com/api/javascript-api/reference/search#m_AMap.DistrictSearch
// https://blog.csdn.net/liujucai/article/details/100070540
AMap.plugin('AMap.DistrictSearch', function() {
var districtSearch = new AMap.DistrictSearch({
// 返回行政区边界坐标等具体信息
extensions: 'all',
// 设置查询行政区级别为 区
//level: 'district',
// 不返回下级行政区
subdistrict: 0
})
districtSearch.search(_this.defaultPara.adcCode, function(
status,
result
) {
if (status === 'complete') {
// 外多边形坐标数组和内多边形坐标数组
var outer = [
new AMap.LngLat(-360, 90, true),
new AMap.LngLat(-360, -90, true),
new AMap.LngLat(360, -90, true),
new AMap.LngLat(360, 90, true)
]
var holes = result.districtList[0].boundaries
var pathArray = [outer]
pathArray.push.apply(pathArray, holes)
var polygon = new AMap.Polygon({
path: pathArray,
// 线条颜色,使用16进制颜色代码赋值。默认值为#006600
strokeColor: 'rgb(122,122,122)',
// 线条宽度
strokeWeight: 2,
// 轮廓线透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.9
strokeOpacity: 0.8,
// 多边形填充颜色,使用16进制颜色代码赋值,如:#FFAA00
fillColor: 'rgba(250, 250, 250, 0.9)',
// 多边形填充透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.9
fillOpacity: 1,
// 轮廓线样式,实线:solid,虚线:dashed
strokeStyle: 'dashed',
// 勾勒形状轮廓的虚线和间隙的样式,此属性在strokeStyle 为dashed 时有效, 此属性在
// ie9+浏览器有效 取值:
// 实线:[0,0,0]
// 虚线:[10,10] ,[10,10] 表示10个像素的实线和10个像素的空白(如此反复)组成的虚线
// 点画线:[10,2,10], [10,2,10] 表示10个像素的实线和2个像素的空白 + 10个像素的实
// 线和10个像素的空白 (如此反复)组成的虚线
strokeDasharray: [0, 0, 0]
})
//polygon.setPath(pathArray)
_this.amapInstance.add(polygon)
// _this.amapInstance.setLimitBounds(polygon.getBounds())
console.log('蒙版绘制polygon完成')
_this.mapMask = polygon
} else if (status === 'error') {
_this.$Message(result, 'error')
}
_this.loading = false
})
})
}
}
- 官网的例子是这么调用的,有一些博客也是这样
new AMap.DistrictSearch({
extensions:'all',
subdistrict:0
})
...
...
然后就会报未定义的错
- 如果你要这么用,要么在代码或index.html中单独引用DistrictSearch插件
<script src="https://webapi.amap.com/maps?v=1.4.15&key=c4f16b4da2e9c9023eac7f81d021bb1b&plugin=AMap.DistrictSearch"></script>
- 要么先调用AMap.plugin引入DistrictSearch插件
AMap.plugin('AMap.DistrictSearch')
效果
https://lbs.amap.com/api/javascript-api/reference/search
https://lbs.amap.com/api/javascript-api/reference/search#m_AMap.DistrictSearch
https://blog.csdn.net/liujucai/article/details/100070540
自定义信息窗体更完美的方法
一般百度搜到的包括官网例子都是:字符串拼接Html
将拼接好的html赋值给marker的content属性,点击marker时设置infowindow的内容,如下
1.
var infoWindow = new AMap.InfoWindow({
offset: new AMap.Pixel(0, -10)
});
for (var i = 0, marker; i < lnglats.length; i++) {
var marker = new AMap.Marker({
position: lnglats[i],
map: map
});
marker.content = '<h3>我是第' + (i + 1) + '个XXX</h3>';
marker.content += '<div>经度:'+lnglats[i][0]+'</div>';
marker.content += '<div>纬度:'+lnglats[i][1]+'</div>';
marker.content += '<div><button class="btn btn-suucess btn-xs">历史轨迹</button>';
marker.content += ' <button class="btn btn-warning btn-xs">实时跟踪 </button>';
marker.content += ' <button class="btn btn-danger btn-xs">设置</button></div>';
marker.on('click', markerClick);
marker.emit('click', {target: marker});
}
function markerClick(e) {
infoWindow.setContent(e.target.content);
infoWindow.open(map, e.target.getPosition());
}
2.
let content = [
'<div class="shipInfoPop">',
'<div class="head" style="color:#333; font-size:16px; border-bottom: 1px solid #d8d8d8;">',
ship.title + ' <span style="color:#548CF9;font-size:14px;">详情</span></div>',
'<ul>',
'<li>船舶信息</li>',
'<li>视频监控</li>',
'<li>天线状态</li>',
'<li>Modem信息</li>',
'<li>运动分析</li>',
'<li>运动轨迹</li>',
'</ul>',
'<div class="info">',
'<p>卫星: '+ ship.satellites +'</p>',
'<p>时间: '+ ship.dateTime +'</p>',
'<p>航向: '+ ship.headingAngle +'</p>',
'<p>航速: '+ ship.speed +'</p>',
'<p>经度: '+ ship.gpsWVal +'</p>',
'<p>纬度: '+ ship.gpsJval +'</p>',
'</div></div>'
];
...
...
在Vue中咱还这么写,嗯… 看起来很蠢的方法,那咱用的还是vue嘛
- 既然是Vue,就要利用Vue的特点 – 组件化 + 数据驱动
接下来就以子组件的形式自定义高德地图的信息窗体
- 首先建立一个xxx.vue文件,名字自己定义就好,要不要在跟地图组件同一个目录下看你自己了,我这里是infoWindow.vue
- 和写其他vue页面一样,template、script、style,这里就不贴具体代码了
ps:子组件的props中定义你要绑定的数据,双向绑定可使用value字段
<template>
<div>
</div>
</template>
<script>
export default {
props: {
deviceInfo: {
type: Object,
default: function() {
return {
baseInfo: {}
extend: []
}
}
}
},
components: {
},
mounted() {
},
data() {
return {
}
},
methods: {
}
}
</script>
<style lang='scss'>
</style>
- 在父组件中引用这个子组件
import infowindow from './infoWindow'
export default {
...
components: {
infowindow
},
...
}
- 添加到页面中,包裹一层div让它不显示,需要用到ref属性!!
<div style="display:none">
<infowindow ref="infowindow"
:deviceInfo="showMarker"
@close="closeInfoWindow"
@getprop="getMarkerProp">
</infowindow>
</div>
- 初始化信息窗体
createInfoWindow() {
// https://blog.csdn.net/qq_39512863/article/details/90483781
this.mapInfoWindow = new AMap.InfoWindow({
// 是否自动调整窗体到视野内(当信息窗体超出视野范围时,通过该属性设置是否自动平移地图,使信息窗体完全显示)
autoMove: true,
// 是否自定义窗体。设为true时,信息窗体外框及内容完全按照content所设的值添加(默认为false,即在系统默认的信息窗体外框中显示content内容)
isCustom: false,
anchor: 'bottom-center',
// 弹出位置偏移量,可根据图标大小修改
offset: new AMap.Pixel(0, -10)
// 控制是否在鼠标点击地图后关闭信息窗体,默认false,鼠标点击地图后不关闭信息窗体
// closeWhenClickMap: true
})
// 这里重点了
this.mapInfoWindow.setContent(this.$refs.infowindow.$el)
this.mapInfoWindow.on('close', this.infoWindowClosed)
},
- OK,内容有了,接下来就是传数据了,前面我们已经给infoWindow绑定了showMarker变量
那么在创建一个标记点的时候,这么做
createMarker(para) {
// https://lbs.amap.com/api/javascript-api/reference/overlay#marker
var marker = new AMap.Marker({
position: new AMap.LngLat(para.lng, para.lat),
offset: new AMap.Pixel(-10, -10),
icon: this.getMarkerIcon(para),
//animation: 'AMAP_ANIMATION_BOUNCE',
title: para.name,
// 鼠标点击时marker是否置顶
topWhenClick: true
})
// 创建一个属性,缓存你需要的数据
marker.data = para
// 绑定点击事件
marker.on('click',this.markerClick)
return marker
},
- 标记点被点击的事件处理,e.target就是你点击的Marker,具体可看官网
这里我们获取到之前缓存在marker实例中的data属性,赋值给 showMarker.baseInfo (你传给子组件的参数)
// 标记点被点击
async markerClick(e) {
console.log('markerClick', e.target)
this.showMarker.baseInfo = e.target.data
var extend = await markerApi.queryProps(e.target.data.id)
this.showMarker.extend = extend ? extend : {}
this.mapInfoWindow.open(this.amapInstance, e.target.getPosition())
},
- 弹出的信息窗体
- 个人认为,这样自定义方便多了,组件里还可以用element-ui的组件,css写的也方便,抛事件也方便,简直完美,何必去拼接html呢
- 差不多就这么多了,至于你要怎么使用绑定值,抛出哪些事件就看你具体要求了
- 还是贴上代码吧(2020.06.04),各位新手可以改改用,这个开始是在高德中用的,不过为了兼容leaflet改了一些东西,高德很久没有测试过了
<template>
<div class="map-infowindow-container">
<div class="map-infoWindow-header"
slot="header">
<div class="map-infoWindow-header-title">
{{deviceInfo.baseInfo.name}}
</div>
</div>
<div class="map-infoWindow-main">
<el-row class="device-prop">
<el-col :span="8">
<el-tag class="device-prop-label"
:type="doorState"
:effect="tagEffect">
{{$t('gisMap.map.deviceInfo.state')}}
</el-tag>
</el-col>
<el-col :span="16">
<span class="device-prop-value">{{formmat('state',deviceInfo.baseInfo.state)}}</span>
</el-col>
</el-row>
<el-row class="device-prop">
<el-col :span="8">
<el-tag class="device-prop-label"
:type="lockState"
:effect="tagEffect">
{{$t('gisMap.map.deviceInfo.lockState')}}
</el-tag>
</el-col>
<el-col :span="16">
<span class="device-prop-value">{{formmat('lockState',deviceInfo.baseInfo.lockState)}}</span>
</el-col>
</el-row>
<el-row class="device-prop">
<el-col :span="8">
<el-tag class="device-prop-label"
type="info"
:effect="tagEffect">
{{$t('gisMap.map.deviceInfo.deptName')}}
</el-tag>
</el-col>
<el-col :span="16">
<span class="device-prop-value">{{deviceInfo.baseInfo.deptName}}</span>
</el-col>
</el-row>
<el-row class="device-prop">
<el-col :span="8">
<el-tag class="device-prop-label"
type="info"
:effect="tagEffect">
{{$t('gisMap.map.deviceInfo.staffName')}}
</el-tag>
</el-col>
<el-col :span="16">
<span class="device-prop-value">{{deviceInfo.baseInfo.staffName}}</span>
</el-col>
</el-row>
<el-row class="device-prop">
<el-col :span="8">
<el-tag type="info"
class="device-prop-label"
:effect="tagEffect">
{{$t('gisMap.map.deviceInfo.location')}}
</el-tag>
</el-col>
<el-col :span="16">
<span class="device-prop-value">{{deviceInfo.baseInfo.lng}},{{deviceInfo.baseInfo.lat}}</span>
</el-col>
</el-row>
<el-row class="device-prop">
<el-col :span="8">
<el-tag class="device-prop-label"
type="info"
:effect="tagEffect">
{{$t('gisMap.map.deviceInfo.desc')}}
</el-tag>
</el-col>
<el-col :span="16">
<span class="device-prop-value">{{deviceInfo.baseInfo.desc}}</span>
</el-col>
</el-row>
<!-- <el-row class="device-prop"
type="flex"
justify="center">
<el-button class="device-prop-viewextend"
type="text"
:disabled="!deviceInfo.baseInfo.hasProps">
{{$t('gisMap.map.viewExtend')}}
<i class="el-icon-arrow-down" /></el-button>
</el-row> -->
<div class="device-extend"
v-loading="loading.extend">
<div class="device-extend-succs"
v-if="showExtend && !isError">
<el-row class="device-prop"
v-for="item in deviceInfo.extend"
:key="item.code">
<el-col :span="8">
<el-tag class="device-prop-label"
type=""
:effect="tagEffect">
{{item.name}}
</el-tag>
</el-col>
<el-col :span="16">
<span class="device-prop-value">
{{item.val}} {{item.unit}}
</span>
</el-col>
</el-row>
</div>
<span class="device-extend-err"
v-if="isError">
{{$t('gisMap.map.getExtendErr')}}
</span>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Map-InfoWindow',
props: {
deviceInfo: {
type: Object,
default: function() {
return {
baseInfo: {
id: null,
name: null,
state: null,
lockState: null,
mainType: null,
subType: null,
lat: null,
lng: null,
desc: null,
deptName: null,
staffName: null,
hasProps: null
},
// code
// name
// val
extend: []
}
}
}
},
computed: {
doorState() {
return this.deviceInfo.baseInfo.state === 0
? 'success'
: this.deviceInfo.baseInfo.state === 1
? 'danger'
: 'warning'
},
lockState() {
return this.deviceInfo.baseInfo.lockState === 0
? 'success'
: this.deviceInfo.baseInfo.lockState === 1
? 'danger'
: 'warning'
},
showExtend() {
return (
this.deviceInfo.baseInfo &&
this.deviceInfo.baseInfo.hasProps &&
this.deviceInfo.extend &&
this.deviceInfo.extend.length > 0
)
}
},
data() {
return {
tagEffect: 'plain',
loading: {
extend: false
},
isError: false
}
},
methods: {
formmat(key, value) {
switch (key) {
case 'state':
return value === 0 ? '关闭' : value === 1 ? '打开' : '未知'
break
case 'lockState':
return value === 0 ? '闭锁' : value === 1 ? '开锁' : '未知'
break
default:
break
}
},
setLoading(name, val) {
if (this.loading[name] != undefined) {
this.loading[name] = val
}
},
setError(val) {
this.isError = val
}
}
}
</script>
<style lang="scss">
.map-infowindow-container {
height: auto;
width: 230px;
.map-infoWindow-header {
height: auto;
word-wrap: break-word;
border-bottom: 1px solid lightgray;
padding: 10px 0px 15px 10px;
.map-infoWindow-header-title {
height: auto;
font-size: 16px;
color: dimgray;
font-weight: bold;
}
}
.map-infoWindow-main {
.device-prop {
margin-top: 8px;
.device-prop-label {
float: right;
}
.device-prop-value {
margin-left: 10px;
font-size: 12px;
word-wrap: break-word;
color: gray;
}
.device-prop-viewextend {
padding: 0 !important;
}
}
.device-extend {
border-top: 1px;
padding-top: 5px;
.device-extend-err {
color: red;
font-size: 12px;
display: flex;
text-align: center;
justify-content: center;
}
}
}
}
</style>
后语
- 贴上参考: https://blog.csdn.net/qq_39512863/article/details/90483781
- 更新记录:
- 2020-03-06:先就写这么多,后面再写
- 2021-03-10:优化部分文字描述
更多推荐
已为社区贡献5条内容
所有评论(0)