Vue2如何实现嵌入百度地图
前端如何嵌入百度地图

这时回到我的应用里,就能看到刚刚申请的两个应用的信息了,访问应用AK就是待会调用地图的关键。
如图所示,本地采用按钮跳转的形式,故而将基于实现背景展开具体实现。
<el-button slot="append" icon="el-icon-location-information" @click="choiceMap()" prop="longitude" readonly/>
至于地图,我则抽出为一个组件
<MapProp ref="map" :single-choice="true" @callData="mapChecked" map_key="project-map"/>
并在components中进行导入
components: {
MapProp
},MapProp 组件代码稍候再贴出并详细讲解,所以这个组件可以在讲解后再进行引入;
先来看看choiceMap方法传入的内容:
choiceMap() {
this.$refs.map.init({
id : this.dataForm.id,
projectAddress: this.dataForm.projectAddress,//详细地址
longitude: this.dataForm.longitude,//经度
latitude: this.dataForm.latitude//纬度
});
},主要用于保存地址信息及进入时默认定位为传入的经纬度,id可以自行判断是否需要传递;
再来看看地图的mapChecked回调方法:
mapChecked(data) {
let province = data.province;//省
let city = data.city;//市
let district = data.district;//区、县
let street = this.dataForm.projectAddress;//保存修改前的地址
this.dataForm.projectAddress = data.address;//详细地址
this.dataForm.longitude = data.addrPoint.lng;//经度
this.dataForm.latitude = data.addrPoint.lat;//纬度
let param = {
province,
city,
district
}
// 根据省市地址获取省市对应的id填入工程地区字段,如果省市为空则表示没有做修改,不做处理
if (street !== this.dataForm.projectAddress) {
getCityIdByProvinceAndCity(param).then((res) => {
this.dataForm.projectAreaids = '[' + res.data.toString() + ']';
// 地址信息
this.dataForm.projectAreaids = JSON.parse(this.dataForm.projectAreaids);
this.isShowProjectAreaidsInfo = false;
this.$nextTick(() => {
this.isShowProjectAreaidsInfo = true;
})
})
}
},三、实现步骤
export default function loadBMap() {
let ak = 'xxxxxx';
return new Promise(function(resolve, reject) {
if (typeof window.BMap !== 'undefined') {
resolve(window.BMap)
return true
}
window.onBMapCallback = function() {
resolve(window.BMap)
}
let script = document.createElement('script')
script.type = 'text/javascript'
script.src =
'https://api.map.baidu.com/api?v=3.0&ak=' + ak + '&callback=onBMapCallback'
script.onerror = reject
document.head.appendChild(script)
})
}代码中的AK就是刚刚在百度开放平台中申请的浏览器端的AK,去复制过来填入即可
2、创建一个组件用于展示地图
也就是上文中提到的MapProp组件,全代码如下(注意:部分代码嵌套了第三方的css文件,需要自行删除,比如包含“DIAN-common-layout”、“DIAN-common-layout-center”的标签,需自行删除):
<template>
<el-dialog :title="title" :visible.sync="visible" class="DIAN-dialog DIAN-dialog_center" lock-scroll append-to-body :close-on-click-modal = "false"
width="98%" @closed="destroyMap">
<div>
<div>
<div>
<el-form ref="form" :model="form" label-width="100px" @submit.native.prevent>
<el-row>
<el-col :span="24">
<el-form-item label="当前地址:" prop="completeAddress">
<el-autocomplete
v-model="form.completeAddress"
style="width:100%;"
popper-class="autoAddressClass"
:fetch-suggestions="querySearchAsync"
:trigger-on-focus="false"
placeholder="详细地址"
clearable
@select="handleSelect"
>
<template slot-scope="{ item }">
<i class="el-icon-search fl mgr10"/>
<div style="overflow:hidden;">
<div>{{ item.title }}</div>
<span class="address ellipsis">{{ item.address }}</span>
</div>
</template>
</el-autocomplete>
</el-form-item>
</el-col>
<!-- <el-col :span="6">-->
<!-- <el-form-item label="位置经度">-->
<!-- <el-input-->
<!-- size="small"-->
<!-- type="text"-->
<!-- v-model="form.addrPoint.lng"-->
<!-- readonly-->
<!-- />-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<!-- <el-col :span="6">-->
<!-- <el-form-item label="位置纬度">-->
<!-- <el-input-->
<!-- size="small"-->
<!-- type="text"-->
<!-- v-model="form.addrPoint.lat"-->
<!-- readonly-->
<!-- />-->
<!-- </el-form-item>-->
<!-- </el-col>-->
</el-row>
<el-form-item label="地图定位:">
<div :id="map_key" style="width:100%;height:70vh;"/><!--395-->
<!-- 遮罩层 -->
<div style="position:absolute;bottom:0;left:0;right:0;height:20px;background-color:white;"></div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">确定</el-button>
<el-button @click="visible = false">{{ $t('common.cancelButton') }}</el-button>
<!-- <el-button type="primary" @click="fixedPosition">定位当前位置</el-button>-->
</el-form-item>
</el-form>
</div>
</div>
</div>
</el-dialog>
</template>
<script>
import loadBMap from "@/api/loadBMap";
import {getNearbyProject} from "@/api/market/projectReport";
import $dian from "@/utils/dian";
export default {
props: {
title: {
default: '选择地址'
},
map_key: {
default: 'map-container'
},
},
data() {
return {
visible: false,// 弹窗显示
form: {
id: '', //项目id
completeAddress: '', //完整地址
province: '', //省份
city: '', // 市级
district: '', // 区、县级
address: '', // 详细地址
addrPoint: { // 详细地址经纬度
lng: '',// 经度
lat: '',// 纬度
}
},
map: '', // 地图实例
mk: '', // Marker实例
}
},
async mounted() {
await loadBMap() // 加载引入BMap
this.initMap()
},
methods: {
async init(data) {
this.visible = true;
this.form.id = data.id;
this.form.completeAddress = data.projectAddress;//完整地址
this.form.address = data.projectAddress;//详细地址
this.form.addrPoint.lng = data.longitude ? data.longitude : '116.2317';//详细地址经纬度
this.form.addrPoint.lat = data.latitude ? data.latitude : '39.5427';//详细地址经纬度
},
// 初始化地图
initMap() {
let point;
const that = this;
// 1、挂载地图
// this.map = new BMap.Map(this.map_key, {enableMapClick: false})// 创建地图实例
// if (this.form.addrPoint.lng && this.form.addrPoint.lat) {// 如果有地址经纬度
// point = new BMap.Point(this.form.addrPoint.lng, this.form.addrPoint.lat);
// } else {
// that.fixedPosition() // 浏览器定位获取当前经纬度
// 2、设置中心点坐标和地图级别
// point = new BMap.Point(this.form.addrPoint.lng, this.form.addrPoint.lat);// 创建点坐标
// }
this.map = new BMap.Map(this.map_key, {enableMapClick: false})// 创建地图实例
point = new BMap.Point(this.form.addrPoint.lng, this.form.addrPoint.lat);
that.getAddrByPoint(point)
this.map.centerAndZoom(point, 15)// 初始化地图,设置中心点坐标和地图级别
//获取周边500米范围内的项目并标记出来
if ($dian.hasPerBtnP('market:projectReport:showProject') && that.form.address) {// 判断是否有权限,以及是否为第二次打开弹窗
this.getAroundProject();
}
// 3、设置图像标注并绑定拖拽标注结束后事件
this.mk = new BMap.Marker(point, {enableDragging: true})// 创建标注
this.map.addOverlay(this.mk)// 添加标注
this.mk.addEventListener('dragend', function (e) {// 拖拽标注结束后事件
that.getAddrByPoint(e.point)// 根据拖拽后的标注点获取详细地址
})
// 4、添加(右上角)平移缩放控件
this.map.addControl(new BMap.NavigationControl({
anchor: BMAP_ANCHOR_TOP_RIGHT,// 控件位置
type: BMAP_NAVIGATION_CONTROL_SMALL// 控件类型
}))
this.map.enableScrollWheelZoom(true); // 允许鼠标滑轮放大缩小
// 5、添加(右下角)定位控件
const geolocationControl = new BMap.GeolocationControl({
anchor: BMAP_ANCHOR_BOTTOM_RIGHT,// 控件位置(右下角)BMAP_ANCHOR_TOP_LEFT\BMAP_ANCHOR_BOTTOM_RIGHT
showAddressBar: true, //是否显示定位信息面板
enableAutoLocation: true, //首次是否进行自动定位
offset: new BMap.Size(6, 22)//偏移距离
});
geolocationControl.addEventListener('locationSuccess', function (e) {// 定位成功事件
that.getAddrByPoint(e.point)
that.$message("地址获取成功")
})
geolocationControl.addEventListener('locationError', function (e) {// 定位失败事件
that.$message.error("定位失败,请稍候再试");
})
this.map.addControl(geolocationControl)// 添加定位控件
// 7、绑定点击地图任意点事件
this.map.addEventListener('click', function (e) {
that.getAddrByPoint(e.point)
})
},
// 浏览器定位获取当前经纬度(不同浏览器的使用会出现问题,暂时弃用)
fixedPosition() {
const that = this;
const geolocation = new BMap.Geolocation();
geolocation.getCurrentPosition(function (r) {
if (this.getStatus() == BMAP_STATUS_SUCCESS) {
that.getAddrByPoint(r.point)
} else {
that.$message.error("定位失败,请手动搜索地址或稍候再试")
}
}, {enableHighAccuracy: true});//是否要求浏览器获取最佳效果,默认为false
},
// 2、逆地址解析函数
getAddrByPoint(point) {
var that = this
var geco = new BMap.Geocoder()// 创建地址解析器实例
geco.getLocation(point, function (res) {// 获取详细地址信息
console.log("地址解析结果:", res)
that.mk.setPosition(point)// 设置Marker位置,点击地图能够实时更新到标注地址
that.map.panTo(point)// 定位到该点
that.map.centerAndZoom(point, that.map.getZoom());//设置中心点坐标并获取当前缩放级别地图级别进行设置
that.form.completeAddress = res.address + res.business + res.content.poi_desc;//设置完整地址
that.form.province = res.addressComponents.province// 设置省份
that.form.city = res.addressComponents.city// 设置市级
that.form.district = res.addressComponents.district// 设置区、县级
that.form.address = that.splitAddress(that.form.completeAddress);//详细地址
that.form.addrPoint = point// 设置详细地址经纬度
})
},
//获取周边500米范围内的项目并标记出来
getAroundProject() {
const that = this;
// 根据返回的经纬度去查询数据库中五百米内项目并展示出来
let param = {
id: that.form.id,
longitude: that.form.addrPoint.lng,
latitude: that.form.addrPoint.lat,
}
var i = 0;
//获取周边五百米内项目
getNearbyProject(param).then((res) => {
const mapPoints = res.data;
//创建多个标注
function markerFun(points) {
// 创建自定义图标
var icon = new BMap.Icon(
require("../../../../../public/cdn/img/bule-marker.png"),
new BMap.Size(100, 100), {
anchor: new BMap.Size(13, 28),// 设置图片锚点
});
var markers = new BMap.Marker(points, {icon: icon});// 创建标注
that.map.addOverlay(markers);// 添加标注
}
for (; i < mapPoints.length; i++) {
var points = new BMap.Point(mapPoints[i].longitude, mapPoints[i].latitude);//创建坐标点
markerFun(points);
}
})
},
// 8-1、地址搜索
querySearchAsync(str, cb) {
var options = {
onSearchComplete: function (res) {
var s = []
if (local.getStatus() == BMAP_STATUS_SUCCESS) {
for (var i = 0; i < res.getCurrentNumPois(); i++) {
var poi = res.getPoi(i);
if (!poi.province) {//如果没有省份信息,则使用搜索结果的省份信息
poi.province = res.province
poi.city = res.city
poi.district = res.district
}
s.push(res.getPoi(i))
}
cb(s)
} else {
cb(s)
}
}
}
var local = new BMap.LocalSearch(this.map, options)// 创建地址搜索实例
local.search(str)// 开始搜索
},
// 8-2、选择地址
handleSelect(item) {
console.log("选择地址结果",item)
if (item.address === item.title) {
this.form.completeAddress = item.address//完整地址
}else {
this.form.completeAddress = item.address + item.title//完整地址
}
this.form.province = item.province//省份
this.form.city = item.city//市级
this.form.district = item.district//区、县级
this.form.address = this.splitAddress(this.form.completeAddress);//详细地址
this.form.addrPoint = item.point//详细地址经纬度
this.map.clearOverlays()// 清除标注
this.mk = new BMap.Marker(item.point)
this.map.addOverlay(this.mk)
this.map.panTo(item.point)
},
//获取选择值
onSubmit() {
let form = this.form;
this.visible = false;
this.$emit('callData', form)
this.destroyMap();
},
// 在对话框关闭时销毁地图实例
destroyMap() {
if (this.map) {
this.map.removeOverlay(this.mk);
this.map.close();// 关闭地图(浏览器会抛出错误,但不影响使用)
this.map = null; // 销毁地图实例
}
if (this.mk) {
this.mk = null; // 清除Marker实例
}
const mapContainer = document.getElementById(this.map_key);
mapContainer.parentNode.removeChild(mapContainer);
},
// 修改地图初始化时机
async handleDialogOpen() {
await loadBMap();
this.$nextTick(() => {
this.initMap();
});
},
// 地址去掉省、市、县或区级单位
splitAddress(address) {
address = address.replace(this.form.province, "");
address = address.replace(this.form.city, "");
address = address.replace(this.form.district, "");
return address;
},
},
// 监听visible变化,打开对话框时初始化地图
watch: {
visible(newValue) {
if (newValue) {
this.handleDialogOpen();
}
},
},
// 组件销毁时销毁地图实例
beforeDestroy() {
this.destroyMap();
},
}
</script>
<style scoped>
> > > .autoAddressClass {
li {
i.el-icon-search {
margin-top: 11px;
}
.mgr10 {
margin-right: 10px;
}
.title {
text-overflow: ellipsis;
overflow: hidden;
}
.address {
line-height: 1;
font-size: 12px;
color: #b4b4b4;
margin-bottom: 5px;
}
}
}
.DIAN-dialog {
>>> .el-dialog__body {
min-height: 90vh;
}
}
</style>展示结果则为最上面的效果图

3、部分代码讲解
(1)搜索框
<el-form-item label="当前地址:" prop="completeAddress">
<el-autocomplete
v-model="form.completeAddress"
style="width:100%;"
popper-class="autoAddressClass"
:fetch-suggestions="querySearchAsync"
:trigger-on-focus="false"
placeholder="详细地址"
clearable
@select="handleSelect"
>
<template slot-scope="{ item }">
<i class="el-icon-search fl mgr10"/>
<div style="overflow:hidden;">
<div class="title">{{ item.title }}</div>
<span class="address ellipsis">{{ item.address }}</span>
</div>
</template>
</el-autocomplete>
</el-form-item>这段代码是上图中的搜索框,实现地址的搜索

(2)地图实例
<el-form-item label="地图定位:"> <div :id="map_key" style="width:100%;height:70vh;"/><!--395--> <!-- 遮罩层 --> <div style="position:absolute;bottom:0;left:0;right:0;height:20px;background-color:white;"> </div> </el-form-item>
这段代码则是实现了地图的渲染及百度地图水印的遮挡,因为百度地图默认是有展示水印的,这里不展示未遮罩前的效果,有兴趣看看的话注释第三行代码即可;
map_key则是渲染的关键,我们看到代码中的mounted钩子:
async mounted() {
await loadBMap() // 加载引入BMap
this.initMap()
},loadBMap就是上文中创建的动态加载百度地图api的.js文件
在methods的init方法中:
this.visible = true; this.form.id = data.id; this.form.completeAddress = data.projectAddress;//完整地址 this.form.address = data.projectAddress;//详细地址 this.form.addrPoint.lng = data.longitude ? data.longitude : '116.2317';//详细地址经纬度 this.form.addrPoint.lat = data.latitude ? data.latitude : '39.5427';//详细地址经纬度
visible 属性用于将页面弹出打开
completeAddress 属性和 address 都是用于保存地址,区别在于一个为绝对路径一个为相对路径
addrPoint.lng和addrPoint.lat为进入地图时默认定位的地址,当传入的longitude和latitude 为空时则会定位到默认的经纬度中,上文默认定位的到北京天安门
再往后的代码后面都有注释,以大家的智商肯定是一看就明白了,重点说一下getAroundProject方法:
getAroundProject() {
const that = this;
// 根据返回的经纬度去查询数据库中五百米内项目并展示出来
let param = {
id: that.form.id,
longitude: that.form.addrPoint.lng,
latitude: that.form.addrPoint.lat,
}
var i = 0;
//获取周边五百米内项目
getNearbyProject(param).then((res) => {
const mapPoints = res.data;
//创建多个标注
function markerFun(points) {
// 创建自定义图标
var icon = new BMap.Icon(
require("../../../../../public/cdn/img/bule-marker.png"),
new BMap.Size(100, 100), {
anchor: new BMap.Size(13, 28),// 设置图片锚点
});
var markers = new BMap.Marker(points, {icon: icon});// 创建标注
that.map.addOverlay(markers);// 添加标注
}
for (; i < mapPoints.length; i++) {
var points = new BMap.Point(mapPoints[i].longitude, mapPoints[i].latitude);//创建坐标点
markerFun(points);
}
})
},这个方法主要用于渲染存在于传入的经纬度周边的标注,可自行选择是否删除,我的应用场景为当定位的地址周边五百米存在项目时就会进行展示,显示效果如下:

用不上的话将相关代码删除即可。
再往后就是地图销毁之类的代码,大部分无需修改,不过选择的具体返回地址信息可以在handleSelect方法中自行定义
handleSelect(item) {
console.log("选择地址结果",item)
if (item.address === item.title) {
this.form.completeAddress = item.address//完整地址
}else {
this.form.completeAddress = item.address + item.title//完整地址
}
this.form.province = item.province//省份
this.form.city = item.city//市级
this.form.district = item.district//区、县级
this.form.address = this.splitAddress(this.form.completeAddress);//详细地址
this.form.addrPoint = item.point//详细地址经纬度
this.map.clearOverlays()// 清除标注
this.mk = new BMap.Marker(item.point)
this.map.addOverlay(this.mk)
this.map.panTo(item.point)
},四,其他注意事项
目前发现部分浏览器会出现定位不准确的情况,也就是点击图中的定位会出现定位不准确的情况

因为情况是偶发性的,会因为浏览器的不同会出现有时会出现,有时不会出现的情况(本人使用谷歌浏览器会出现),因为定位是根据网络定位,实验多次后发现使用微信自带的浏览器是最准确的,具体原因不详,提前给大家提个醒。
:




