需求 & 图例
标题功能分为2部分的需求:
- 【原需求】填写地址:省市区(下拉)+详情(输入),
【新需求】原需求保持不变,但是增加快捷方式选择地址,a.增加地图搜索选中后 回填地址 b.常用地址/历史地址 列表,选中后 回填地址;
图示说明:
所有图示案例均为代码功能展示用,不考虑美观性。
- 地理编码:地址转为经纬度;逆地理编码:经纬度转为地址;
【需求】:地图打开中心点默认在ip所在的城市;根据历史GPS数据展示车辆的历史轨迹信息,点击轨迹点展示信息窗体,右侧展示中显示当前车辆的所在的经纬度对应的详细地址;
图示3:(中心点默认在ip所在的城市)
图示4:(根据GPS数据展示车辆历史轨迹,基于后端返回的数据展示)
图示5:(前端模拟数据,展示轨迹,点击展示信息窗体,右侧展示逆地理编码信息)
main.js
import VueAMap from 'vue-amap'; // 命名尽量与AMap做区分
Vue.use(VueAMap);
VueAMap.initAMapApiLoader({
key: 'your key',
plugin: [
"AMap.Autocomplete",
"AMap.PlaceSearch",
"AMap.Scale",
"AMap.ToolBar",
"AMap.OverView",
'AMap.MapType',
'AMap.PolyEditor',
'AMap.CircleEditor',
"AMap.Geolocation",
"AMap.Geocoder",
"AMap.CitySearch",
],
v: '1.4.15',
uiVersion: "1.1"
});
window._AMapSecurityConfig = {
securityJsCode: 'your security js code',
}
结构以图例1、2 为基础,其他的功能仅以逻辑为主,以说明为准
所有样式代码均省略
省市区下拉是通过访问后端接口,这里需要将地图选点中获得的省市区的名字传给后端,得到下拉需要的codes
常用/历史 选点列表是通过后端接口获得,接口逻辑略,只展示数据结构
map-dialog.vue
template
{{ scope.row.province+scope.row.city+scope.row.district }}
选择
script
import { GET_CITYS_CODES } from '@/api/xx/index.js'; // 用地图得到的省市区名称换省市区下拉codes
export default {
props: {
params: {
type: Object,
default: {},
},
},
data() {
let self = this;
return {
activeName: "first",
amap: {
zoom: 9,
center: [0, 0],
plugin:['ToolBar'],
marker: [0, 0],
events: {
click(e) { self.markerClick(e) }, // 选点点击事件
dragend(e) { self.dragEnd(e) }, // 选点拖拽事件
}
},
searchOption: {
city: '',
citylimit: true
},
// dataList本来是后端接口获得,这里不重要,只作数据结构展示
dataList: [{
province: "四川省",
city: "成都市",
district: "高新区",
address: "仁和街阿斯顿路250号",
codes: ['510000', '510100', '510107']
}],
obj: {},
addr: ""
}
},
methods: {
// 可以放在专门的utils文件中,这里为了方便展示,放在methods里
// 获取当前ip所在城市
getCurrentCity() {
return new Promise((resolve, reject) => {
let city;
AMap.plugin('AMap.CitySearch',function(){
city = new AMap.CitySearch()
})
city.getLocalCity(function (status, result) {
if (status === 'complete' && result.info === 'OK') {
resolve(result.bounds.oc)
} else {
reject('未检测到该地址')
}
});
})
},
// 可以放在专门的utils文件中,这里为了方便展示,放在methods里
// 逆地理编码:经纬度转为地址;
getPositionByLonLats(lnglat) {
return new Promise((resolve, reject) => {
let geocoder;
AMap.plugin('AMap.Geocoder',function(){
geocoder = new AMap.Geocoder()
})
geocoder.getAddress(lnglat, function (status, result) {
if (status === 'complete' && result.info === 'OK') {
resolve(result.regeocode)
} else {
reject('未检测到该地址')
}
});
})
},
// 可以放在专门的utils文件中,这里为了方便展示,放在methods里
// 地理编码:地址转为经纬度(与逆地理编码类似,这里不在演示调用)
getPositionByAddr(addr) {
return new Promise((resolve, reject) => {
let geocoder;
AMap.plugin('AMap.Geocoder',function(){
geocoder = new AMap.Geocoder()
})
geocoder.getLocation(addr, function (status, result) {
if (status === 'complete' && result.geocodes.length) {
resolve(result.geocodes[0].location)
} else {
reject('未检测到该地址')
}
});
})
},
// 弹窗open事件:中心点默认在设在ip所在地址
setData() {
this.getCurrentCity().then((res) => {
this.amap.center = [];
this.amap.center.push(res.lng, res.lat);
})
},
// 点击搜索列表结果
// 注意:返回的结果是数组,默认选中第一个,作为点坐标
async onSearchResult(pois) {
let self = this;
await this.getPositionByLonLats([pois[0].lng, pois[0].lat]).then((res) => {
self.obj = { ...res.addressComponent };
self.addr = res.formattedAddress;
}).catch((err) => {
errorMsg(err);
return
})
self.amap.center = [];
self.amap.center.push(pois[0].lng, pois[0].lat);
self.amap.marker = [];
self.amap.marker.push(pois[0].lng, pois[0].lat);
self.amap.zoom = 18;
},
// 点坐标拖拽结束
dragEnd(e) {
let self = this;
//
self.getPositionByLonLats([e.lnglat.lng, e.lnglat.lat]).then((res) => {
self.obj = { ...res.addressComponent };
self.addr = res.formattedAddress;
}).catch((err) => {
errorMsg(err);
return
})
},
// 点击点坐标,是否确认选择
markerClick() {
let self = this;
self.$confirm(`是否确认选择【${this.addr}】?`, "确认选择", {
closeOnClickModal: false,
cancelButtonClass: "cancel-btn",
confirmButtonClass: "delete-btn",
}).then(() => {
let a = self.obj.province;
let b = self.obj.city;
let c = self.obj.district;
// 将点坐标省市区名称传给后端,获取省市区下拉codes
// 注意:直辖市,高德不会返回市名称,后端要求,直辖市 省市同名
GET_CITYS_CODES([a, b?b:a, c]).then((res) => {
if (res.code === 10000) {
let info = {
address: self.obj.township+self.obj.street+self.obj.streetNumber,
codes: res.result
}
// 将确认信息传给父组件
self.cancel(info);
}
});
})
.catch(() => {});
},
// 常用/历史列表 选择按钮
selectData(data) {
let info = {
address: data.address,
codes: data.codes
}
// 将选择信息传给父组件
this.cancel(info);
},
其他功能的
template
// 结构与前面的template类似,这里只保留el-amap
{{ info.waybillNo }}
{{ info.plate }}
{{ info.phone }}
{{ info.address }}
script
data() {
return {
// 其他类似的略
info: {}, // 信息窗体
infoList: [] // 信息窗体集合
}
},
methods: {
// 点击坐标点弹出 信息窗体
markerClick(e) {
let self = this;
// 第一次点击 才给所有的信息窗体赋值(为了演示方便放在这里,赋值操作根据实际需求正常操作)
if (self.infoList.length !== self.pathData.length) {
for (let i = 0; i < self.pathData.length; i++) {
let obj = {...self.pathData[i]};
obj.visible = false
self.infoList.push(obj);
}
// 切换信息窗体手动关闭所有窗体的visible
} else {
for (let i = 0; i < self.infoList.length; i++) {
self.infoList[i].visible = false
}
}
// 清空上一个信息窗体的信息
self.info = {};
let arr = [e.target.w.position.lng, e.target.w.position.lat];
let index = self.pathData.findIndex(i => i.marker.toString() === arr.toString());
this.$nextTick(() => {
self.info = self.infoList[index];
self.$set(self.info, 'visible', true);
})
},
}