百度地图
一、申请百度地图的密钥
白名单要为 *
创建成功
二、官方示例
比较有意思的几个案例
三、使用vue整合百度地图步骤说明
3.1 效果图:
说明:
- 搜索检索位置,获取经纬度
- 地图标点反解析出经纬度
3.2 方式一 vue脚手架2.0版本引用(不推荐):
- 在index.html引入
<script async type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=你的ak"></script>
- 在 webpack.base.conf.js 添加externals.BMap配置,与entry平级,内容如下
entry: {
app: ['babel-polyfill', './src/main.js']
},
externals: {
BMap: 'BMap'
}
说明:vue-cli 3.0+ 的版本已经取消了webpack.conf这些文件了,所以上面的方法就不适用了,而且耗费性能
其实在config里面也可以使用,但是不推荐:
3. 在组件中引入BMap
3.3 方式二 封装成js引用(推荐做法):
3.3.1 封装loadBMap.js
export default function loadBMap() {
return new Promise(function(resolve, reject) {
if (typeof window.BMap !== 'undefined') {
resolve(window.BMap)
return true
}
window.onBMapCallback = function() {
resolve(window.BMap)
}
const 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)
})
}
位置:
3.3.2 在组件中引入封装的loadBMap
import loadBMap from "@/utils/loadBMap.js";
3.3.3 在mounted中调用 loadBMap()
async mounted() {
await loadBMap() // 加载引入BMap,封装的js
this.initMap()//这个是初始化地图的方法,在method中定义
},
这样组件基本准备完成,可以根据百度官方示例进行编写
四、整合详解(单独地图页面)
4.1、直接上完整代码,代码注释详解
<template>
<!-- 定义大个盒子 -->
<div class="app-container">
<!--使用element ui -->
<el-form ref="form" :model="form" label-width="110px">
<!-- 检索框部分 -->
<el-form-item label="详细地址:" prop="address">
<el-autocomplete
v-model="form.address"
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>
<!-- 地图盒子 -->
<el-form-item label="地图定位:">
<div id="map-container" style="width:100%;height:500px;" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">提交</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
// 引入封装的js
import loadBMap from '@/utils/loadBMap.js'
export default {
data() {
return {
form: {
address: '', // 详细地址
addrPoint: { // 详细地址经纬度
lng: 0,
lat: 0
}
},
map: '', // 地图实例
mk: '', // Marker实例
locationPoint: null
}
},
async mounted() {
await loadBMap() // 加载引入BMap
this.initMap()//初始化地图
},
methods: {
// 初始化地图的方法
initMap() {
var that = this
// 1、挂载地图
this.map = new BMap.Map('map-container', { enableMapClick: false })
var point = new BMap.Point(113.3324436, 23.1315381)//设置个默认标点
this.map.centerAndZoom(point, 19)
// 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 }))
// 5、添加(左下角)定位控件
var geolocationControl = new BMap.GeolocationControl({ anchor: BMAP_ANCHOR_BOTTOM_LEFT })
geolocationControl.addEventListener('locationSuccess', function(e) {
that.getAddrByPoint(e.point)
})
geolocationControl.addEventListener('locationError', function(e) {
alert(e.message)
})
this.map.addControl(geolocationControl)
// 6、浏览器定位
this.geolocation()
// 7、绑定点击地图任意点事件
this.map.addEventListener('click', function(e) {
that.getAddrByPoint(e.point)
})
},
// 获取两点间的距离
getDistancs(pointA, pointB) {
return this.map.getDistance(pointA, pointB).toFixed(2)
},
// 浏览器定位函数
geolocation() {
var that = this
var geolocation = new BMap.Geolocation()
geolocation.getCurrentPosition(function(res) {
if (this.getStatus() == BMAP_STATUS_SUCCESS) {
that.getAddrByPoint(res.point)
that.locationPoint = res.point
} else {
alert('failed' + this.getStatus())
console.log('failed' + this.getStatus())
that.locationPoint = new BMap.Point(113.3324436, 23.1315381)
}
}, { enableHighAccuracy: true })
},
// 2、逆地址解析函数
getAddrByPoint(point) {
var that = this
var geco = new BMap.Geocoder()
geco.getLocation(point, function(res) {
console.log(res)
that.mk.setPosition(point)
that.map.panTo(point)
that.form.address = res.address
that.form.addrPoint = point
})
},
// 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++) {
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) {
this.form.address = item.address + item.title
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)
},
//点击确定输出form表单的内容
onSubmit() {
console.log(this.form)
}
}
}
</script>
<!-- 样式 -->
<style lang="scss" 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;
}
}
}
</style>
五、地图为子组件,点击触发按钮,展示地图(更常见,详解)
5.1效果图
1、 点击选择,打开地图的组件
2、检索功能,也能在地图自己标点
3、提示信息
3、回显数据,地图组件将数据传输给父组件,父组件取
第一步,一样先引入封装好的js文件
5.2 在主页面引入js,点击按钮调用地图初始化方法
引入js
import loadBMap from '@/utils/loadBMap.js'
钩子方法加载
created() {
// 地图
loadBMap()// 加载引入BMap
}
引入地图组件
//说明@afterSelectPosition="afterSelectPosition"这个是绑定的方法
//用于子组件(地图)给父组件通信(传值)
<selectPosition ref="selectPositionWin" @afterSelectPosition="afterSelectPosition" />
在主页面点击选择,展开地图
点击触发地图的方法
selectPosition() {
// 调用子组件(地图)的初始化方法
this.$refs.selectPositionWin.myMehod()
},
5.3完整的子组件地图代码(dialog包裹)
要点说明
- 使用父组件触发子组件地图,子组件(地图)必须使用 $nextTick 方法,不会第一次会看不到地图,第二次才有
- 子组件向父组件通信是采用$emit方法
- 小编使用的是vue+element+百度地图
$nextTick说明:
Vue.nectTick()介绍: 是在下次DOM更新循环结束之后执行延迟回调,在修改数据之后使用$nextTick,则可以在回调中获取更新后的DOM(dom的改变是发生在nextTick()之后),这个方法作用是当数据被修改后使用这个方法,会回调获取更新后的dom再render出来
Vue.nextTick()作用:在下次dom更新循环结束之后,执行延迟回调。在修改数据之后立即使用这个方法,获得更新后的dom
<template>
<!-- dialogShow绑定对话框是否展示,默认为false-->
<el-dialog :visible.sync="dialogShow" :title="dialogTitle" :close-on-click-modal="false" append-to-body top="5vh"
width="900px" height="400px">
<!-- 大盒子-->
<div class="app-container">
<!-- element ui -->
<el-form ref="form" :model="form" label-width="110px">
<!-- 检索框-->
<el-form-item label="详细地址:" prop="address">
<el-autocomplete
v-model="form.address"
style="width: 700px"
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>
<!-- 地图的盒子-->
<el-form-item label="地图定位:">
<div id="map-container" style="width: 700px; height: 350px"/>
</el-form-item>
<!-- 按钮事件-->
<el-form-item>
<el-button type="primary" @click="onSubmit">确定</el-button>
<el-button @click="handleClose">取消</el-button>
</el-form-item>
</el-form>
</div>
</el-dialog>
</template>
<script>
/* 无须在引入,因为在父组件已经引入了 */
//import loadBMap from "@/utils/loadBMap.js";
export default {
data() {
return {
dialogShow: false,//对话框状态
dialogTitle: '地图定位',
form: {
address: "", // 详细地址
addrPoint: {
// 详细地址经纬度
lng: 0,
lat: 0,
},
},
map: "", // 地图实例
mk: "", // Marker实例
locationPoint: null,
};
},
methods: {
//必须使用$nextTick不然第一次地图会初始化失败,第二次才看得地图
// 必须使用$nextTick不然地图的创建坐标会比地图挂载还快。第一次会初始化失败
myMehod() {
//将对话框状态改为true,也就是打开对话框
this.dialogShow = true
this.$nextTick(() => {
this.initMap()
})
},
// 初始化地图
initMap() {
var that = this;
// 1、挂载地图
this.map = new BMap.Map("map-container", {enableMapClick: false});
var point = new BMap.Point(119.30244559059787, 26.106339983665546);//默认点位
this.map.centerAndZoom(point, 19);
// 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,
})
);
// 5、添加(左下角)定位控件
var geolocationControl = new BMap.GeolocationControl({
anchor: BMAP_ANCHOR_BOTTOM_LEFT,
});
geolocationControl.addEventListener("locationSuccess", function (e) {
that.getAddrByPoint(e.point);
});
geolocationControl.addEventListener("locationError", function (e) {
//alert(e.message);
console.log("locationError", e.message)
});
this.map.addControl(geolocationControl);
// 6、浏览器定位
this.geolocation();
// 7、绑定点击地图任意点事件
this.map.addEventListener("click", function (e) {
that.getAddrByPoint(e.point);
});
},
// 获取两点间的距离
getDistancs(pointA, pointB) {
return this.map.getDistance(pointA, pointB).toFixed(2);
},
// 浏览器定位函数
geolocation() {
var that = this;
var geolocation = new BMap.Geolocation();
geolocation.getCurrentPosition(
function (res) {
if (this.getStatus() == BMAP_STATUS_SUCCESS) {
that.getAddrByPoint(res.point);
that.locationPoint = res.point;
} else {
//alert("failed" + this.getStatus());
console.log("failed", this.getStatus())
that.locationPoint = new BMap.Point(119.30244559059787, 26.106339983665546);
}
},
{enableHighAccuracy: true}
);
},
// 2、逆地址解析函数
getAddrByPoint(point) {
var that = this;
var geco = new BMap.Geocoder();
geco.getLocation(point, function (res) {
//console.log(res);
that.mk.setPosition(point);
that.map.panTo(point);
that.form.address = res.address;
that.form.addrPoint = point;
});
},
// 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++) {
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) {
this.form.address = item.address + item.title;
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() {
// console.log('纬度:',this.form.addrPoint.lat);
// console.log('经度:',this.form.addrPoint.lng);
//传输数据
this.$emit('afterSelectPosition', this.form)//子组件向父组件通信
//提示框
this.$confirm('地址确定好了吗, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
//将对话框状态改为false,也就是关闭对话框
this.dialogShow = false
//将文本域数据清空,不然第二次进来会有数据
this.form.address = ''
})
},
handleClose() {
//将对话框状态改为false,也就是关闭对话框
this.dialogShow = false
//提示
this.$message({
type: 'success',
message: "关闭地图"
})
//将文本域数据清空,不然第二次进来会有数据
this.form.address = ''
}
},
};
</script>
<style lang="scss" 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;
}
}
}
</style>
5.4 说明下组件通信
// 子组件
this.$emit('afterSelectPosition', this.form)
//父组件
<selectPosition ref="selectPositionWin" @afterSelectPosition="afterSelectPosition" />
重点在 @afterSelectPosition="afterSelectPosition"
//说明
afterSelectPosition这个必须一样,名字随便取,
@afterSelectPosition这个是父组件取值的方法
//父组件取值的方法
afterSelectPosition(data) {
this.dataForm.mapLng = data.addrPoint.lng
this.dataForm.mapLat = data.addrPoint.lat
}
六、其他用法说明
- 比如在一个范围内的打卡
- 硬件定位超出地图规定范围预警等一系列操作
- 获取多个经纬度的地点,在地图上使用标点显示
- 路线导航功能
- …
还有不少用处,示例可以借鉴于百度地图api的示例demo ==> 入口
完结