vue-amap安装和使用
vue-amap 是饿了么开源的一套基于 Vue 2.0 和高德地图的地图组件。 数据状态与地图状态单向绑定,开发者无需关心地图的具体操作。
官方文档:https://elemefe.github.io/vue-amap/#/zh-cn/introduction/install
步骤如下:
npm install vue-amap --save
import VueAMap from "vue-amap"
Vue.use(VueAMap)
// 初始化vue-amap
VueAMap.initAMapApiLoader({
key: "amapKey",
plugin: ["AMap.Autocomplete", "AMap.Geocoder", "AMap.Geolocation"],
v: "1.4.15",
uiVersion: "1.1"
})
实例需求描述:搜索并选择地址,选中后地图定位到该地址,并获取经纬度自动填入下方的输入框中。点击地图中的点也自动更新地址和坐标。
定义地图搜索组件
<template>
<div>
<div class="search-box">
<el-input
v-model="searchKey"
type="search"
id="search"
placeholder="请输入详细地址"
></el-input>
<!--<button @click="searchByHand">搜索</button>-->
<div class="tip-box" id="searchTip"></div>
</div>
<!--
amap-manager: 地图管理对象
vid:地图容器节点的ID
zooms: 地图显示的缩放级别范围,在PC上,默认范围[3,18],取值范围[3-18];在移动设备上,默认范围[3-19],取值范围[3-19]
center: 地图中心点坐标值
plugin:地图使用的插件
events: 事件
-->
<div class="amap-box">
<el-amap
:amap-manager="amapManager"
:vid="'amap-vue'"
:zoom="zoom"
:plugin="plugin"
:center="center"
:events="events"
>
<!-- 标记 -->
<el-amap-marker
v-for="(marker, index) in markers"
:position="marker"
:key="index"
></el-amap-marker>
</el-amap>
</div>
</div>
</template>
<script>
import {AMapManager, lazyAMapApiLoaderInstance} from 'vue-amap'
let amapManager = new AMapManager()
export default {
props: ['city', 'value', 'longitude', 'latitude', 'isEdit'],
data() {
let self = this
return {
address: null,
searchKey: '',
amapManager,
markers: [],
searchOption: {
city: this.city ? this.city : '全国',
citylimit: true
},
center: [121.329402, 31.228667],
zoom: 17,
lng: 0,
lat: 0,
loaded: false,
events: {
init() {
lazyAMapApiLoaderInstance.load().then(() => {
self.initSearch()
})
},
// 点击获取地址的数据
click(e) {
self.markers = []
let {lng, lat} = e.lnglat
self.lng = lng
self.lat = lat
self.center = [lng, lat]
self.markers.push([lng, lat])
// 这里通过高德 SDK 完成。
let geocoder
AMap.plugin(['AMap.Geocoder'], function() {
geocoder = new AMap.Geocoder({
radius: 1000,
extensions: 'all'
})
})
geocoder.getAddress([lng, lat], function(status, result) {
if (status === 'complete' && result.info === 'OK') {
if (result && result.regeocode) {
self.address = result.regeocode.formattedAddress
self.searchKey = result.regeocode.formattedAddress
self.poiPicker.clearSearchResults()
self.$emit('updateLocation', lng, lat, self.searchKey)
self.$nextTick()
}
}
})
}
},
// 一些工具插件
plugin: [
{
// 定位
pName: 'Geolocation',
events: {
init(o) {
// o是高德地图定位插件实例
o.getCurrentPosition((status, result) => {
if (result && result.position) {
if (self.isEdit) {
// 设置经度
self.lng = self.longitude
// 设置维度
self.lat = self.latitude
// 设置坐标
self.center = [self.longitude, self.latitude]
self.markers.push([self.longitude, self.latitude])
} else {
console.info('result-->', result)
var address = result.addressComponent.city
self.updateAddress(address, result.position.lng, result.position.lat)
self.poiPicker.searchByKeyword(self.searchKey)
}
// load
self.loaded = true
// 页面渲染好后
self.$nextTick()
}
})
}
}
}
]
}
},
created() {
if (this.value) {
this.searchKey = this.value
this.address = this.value
}
if (this.longitude && this.latitude) {
this.lng = this.longitude
this.lat = this.latitude
this.center = [this.longitude, this.latitude]
this.markers.push([this.longitude, this.latitude])
}
AMap.plugin(['AMap.Geolocation'], () => {
var geolocation = new AMap.Geolocation({
enableHighAccuracy: true, // 是否使用高精度定位,默认:true
timeout: 2000, // 超过2秒后停止定位,默认:无穷大
zoomToAccuracy: false, // 定位成功后地图放最大,默认:false
buttonPosition: 'LB', // 定位器左上下角
buttonOffset: new AMap.Pixel(11, 20), // 定位器位置偏移
showMarker: false
})
AMap.addControl(geolocation)
})
},
methods: {
// 选择地址后自动定位到当前地址附近
updateAddress(value, longitude, latitude) {
this.searchKey = value
this.address = value
this.lng = longitude
this.lat = latitude
this.center = [longitude, latitude]
this.markers.push([longitude, latitude])
},
initSearch() {
let vm = this
let map = this.amapManager.getMap()
AMapUI.loadUI(['misc/PoiPicker'], function(PoiPicker) {
let poiPicker = new PoiPicker({
input: 'search',
placeSearchOptions: {
map: map,
pageSize: 8
},
suggestContainer: 'searchTip',
searchResultsContainer: 'searchTip'
})
vm.poiPicker = poiPicker
// 监听poi选中信息
poiPicker.on('poiPicked', function(poiResult) {
let source = poiResult.source
let poi = poiResult.item
if (source !== 'search') {
poiPicker.searchByKeyword(poi.name)
} else {
poiPicker.clearSearchResults()
vm.markers = []
let lng = poi.location.lng
let lat = poi.location.lat
// let address = poi.name // poi.cityname + poi.adname + poi.name
let address = poi.pname + poi.cityname + poi.adname + poi.address + poi.name
vm.center = [lng, lat]
vm.markers.push([lng, lat])
vm.lng = lng
vm.lat = lat
vm.address = address
vm.searchKey = address
vm.$emit('updateLocation', lng, lat, vm.searchKey)
}
})
})
},
searchByHand() {
if (this.searchKey !== '' && this.poiPicker) {
this.poiPicker.searchByKeyword(this.searchKey)
}
}
}
}
</script>
<style scoped>
.search-box {
margin-top: 6px;
width: 100%;
}
.search-box input {
padding: 0 15px;
width: 100%;
height: 32px;
line-height: 32px;
color: #606266;
border: 1px solid #dcdfe6;
border-radius: 4px;
}
.search-box input:focus {
border-color: #409eff;
outline: 0;
}
.search-box input::-webkit-input-placeholder {
color: #c0c4cc;
}
.tip-box {
width: 100%;
max-height: 580px;
position: absolute;
top: 35px;
z-index: 10000;
overflow-y: auto;
background-color: #fff;
}
.amap-ui-poi-picker-sugg,
.amap_lib_placeSearch {
border: 1px solid #eee;
border-radius: 4px;
}
.amap-box {
height: 400px;
}
</style>
在组件中使用地图搜索组件,这里使用弹窗
<template>
<el-dialog
:title="title"
:visible.sync="visible"
:before-close="handleClose"
width="60%"
append-to-body
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<div class="form-info">
<el-form
:model="form"
ref="form"
:rules="rules"
size="small"
label-width="110px"
>
<el-form-item label="选择地址" prop="address">
<base-map-search
ref="mapSearch"
:city="form.city"
:value="form.address"
:longitude="form.lng"
:latitude="form.lat"
:isEdit="isEdit"
@updateLocation="updateLocation"
/>
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item prop="lng" label="经度">
<el-input
v-model.number="form.lng"
:maxlength="15"
placeholder="请输入经度"
></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="right-label-form-item">
<el-form-item prop="lat" label="纬度">
<el-input
v-model.number="form.lat"
:maxlength="15"
placeholder="请输入纬度"
></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="success" @click="handleSave">保存</el-button>
</div>
</el-dialog>
</template>
<script>
import BaseMapSearch from '@/components/common/baseMapSearch'
export default {
props: ['visible', 'isEdit', 'detail'],
components: {
BaseMapSearch
},
data() {
return {
title: '添加地址',
form: {
address: '',
lng: '',
lat: ''
},
rules: {
address: [
{
required: true,
message: '地址不为空',
trigger: ['blur', 'change']
}
],
lng: [
{
required: true,
message: '经度不为空',
trigger: ['blur', 'change']
}
],
lat: [
{
required: true,
message: '纬度不为空',
trigger: ['blur', 'change']
}
]
}
}
},
created() {
if (this.isEdit) {
this.initForm()
}
},
methods: {
// 初始化表单
initForm() {
this.title = '修改地址'
if (this.detail) {
this.form = {...this.detail}
}
},
// 地图搜索选址
updateLocation(lng, lat, address) {
this.form.lng = lng
this.form.lat = lat
this.form.address = address
},
handleClose() {
this.$emit('closeVisible', false)
},
handleSave() {
this.$refs.form.validate(valid => {
if (!valid) {
return
}
this.$emit('saveMap', this.form)
this.$emit('closeVisible', false)
})
}
}
}
</script>
如果项目中使用了ESlint,会报AMap、AMapUI未定义的错误,我们需要在.eslintrc.js文件中定义globals属性:
module.exports = {
// ...
globals: {
AMap: false,
AMapUI: false
}
}
效果: