项目需求
- 进入地图地址没传经纬度显示当前定位地址,传入经纬度,使用传入位置
- 信息弹框定位到地址Marker点上方
- 长按地址实现地址的复制
- 点击导航按钮底部弹出地图选择(根据手机系统下载的地图)
开发前准备
- 申请账号和秘钥 百度地图开发平台
- 项目根目录index.html中引用地图
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title id="zy-title"></title>
<script
type="text/javascript"
src="https://api.map.baidu.com/api?v=2.0&ak=你申请的秘钥"
></script>
</head>
<body style="visibility: hidden;">
<div id="app"></div>
</body>
</html>
坑一: 基于BMapLib.InfoBox自定义弹框
原因:百度地址自带的信息窗口弹框(InfoWindow)不满足需求的样式,因此需要使用自定义信息窗口,故需要额外引入百度开源类库InfoBox_min.js
百度地址所有开源库:百度开源库地址
<script type="text/javascript" src="https://api.map.baidu.com/library/InfoBox/1.2/src/InfoBox_min.js"></script>
信息弹框实现
getHtml() {
const html = `<div class="box-content">
<div class="box-content-left">
<span class="address-text double-line-ellipsis">${this.address}</span>
</div>
<div class="box-content-right" >
<button class="btn" id="btn">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="0.3rem" height="0.3rem" viewBox="0 0 30 31" version="1.1">
<title>导航icon</title>
<g id="月底" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1.2地址详情页备份" transform="translate(-567.000000, -745.000000)" fill="#FFFFFF" fill-rule="nonzero">
<g id="编组-2" transform="translate(25.000000, 697.538462)">
<g id="编组" transform="translate(500.000000, 18.500000)">
<g id="导航icon" transform="translate(42.000000, 29.000000)">
<path d="M4.89231976,10.7884564 L25.2131095,2.05686699 C26.2279586,1.62079905 27.4041592,2.08999383 27.8402271,3.10484285 C28.0639952,3.62561229 28.0562853,4.21687246 27.8190143,4.73163008 L18.5776304,24.780734 C18.1152486,25.7838675 16.9272137,26.2222333 15.9240802,25.7598515 C15.369156,25.5040661 14.9616056,25.008637 14.8176179,24.4148066 L13.3099188,18.1967912 C13.1460879,17.521124 12.6431229,16.9790163 11.981604,16.7651017 L5.06652675,14.5289816 C4.01554072,14.1891255 3.43905599,13.0616252 3.77891207,12.0106392 C3.95641149,11.4617321 4.36228623,11.0162051 4.89231976,10.7884564 Z" id="路径"/>
</g>
</g>
</g>
</g>
</g>
</svg>
<span class="btn-txt">导航</span>
</button>
</div>
</div>`
return html
},
async function customInfoBox(map, marker) {
let infoBox = new BMapLib.InfoBox(map, this.getHtml(), {
boxStyle: {
background: '#fff',
width: '7rem',
borderRadius: '0.16rem',
boxShadow: '0 2px 4px 0 rgba(0,0,0,0.2)',
zIndex: 999,
padding: '0.4rem 0.2rem',
align: INFOBOX_AT_TOP
},
// 隐藏关闭按钮
closeIconMargin: '1px -50px 0 0',
closeIconUrl: closeImage,
enableAutoPan: true,
offset: new BMap.Size(0, 17)
})
if (this.lastInfoBox && this.lastInfoBox !== null) {
this.lastInfoBox.close()
this.lastInfoBox = null
} else {
infoBox.open(marker)
this.lastInfoBox = infoBox
await this.$nextTick()
this.handleDom()
}
},
坑二:在自定义弹框中添加点击事件没有反应
解决办法: 引入百度的事件包装器库
<script
type="text/javascript"
src="https://api.map.baidu.com/library/EventWrapper/1.2/src/EventWrapper.min.js"
></script>
使用:
/**
*绑定导航事件&长按复制
*/
function handleDom() {
const btn = document.querySelector('#btn')
if (btn && btn !== null) {
// 绑定导航事件
BMapLib.EventWrapper.addDomListener(btn, 'touchend', () => {
this.navigation()
})
}
const addressDom = document.querySelector('.address-text')
if (addressDom && addressDom !== null) {
// 地址长按
BMapLib.EventWrapper.addDomListener(
addressDom,
'touchstart',
() => {
clearTimeout(this.loop)
this.loop = setTimeout(() => {
addressDom.style.background = `#EBF2FD`
this.customCopyModal(addressDom)
}, 1000)
},
false
)
BMapLib.EventWrapper.addDomListener(
addressDom,
'touchend',
() => {
clearTimeout(this.loop)
},
false
)
}
}
具体需求代码实现
<template>
<div class="mapPage">
<div id="allmap" ref="allmap"></div>
</div>
</template>
<script>
import BMap from 'BMap'
import closeImage from '../../assets/archives/close.png'
import BMapLib from 'BMapLib'
export default {
data() {
return {
address: '',
company: '',
point: {}
}
},
mounted() {
this.loop = null
this.lastInfoBox = null
this.address = this.$route.query.address
this.company = this.$route.query.company
this.city = this.$route.query.city
setTimeout(() => {
this.baiduMap(this.address, this.company)
}, 300)
},
methods: {
baiduMap(address) {
// 实例化百度地图对象
const that = this
let map = new BMap.Map(this.$refs.allmap)
// 设置地图中心=点 默认深圳
let point = new BMap.Point(114.02597366, 22.54605355)
map.centerAndZoom(point, 12)
// 允许滚轮缩放
map.enableScrollWheelZoom(true)
map.enableContinuousZoom(true)
// 将地址解析结果显示在地图上,并调整地图视野
// lng经度 lat 纬度
const { lng, lat } = this.$route.query
if (lng && lat) {
that.point = new BMap.Point(lng, lat)
that.createdMarker(that.point, map)
} else {
// 创建地址解析器实例
let myGeo = new BMap.Geocoder()
myGeo.getPoint(
address,
function(point) {
if (point) {
that.point = point
that.createdMarker(point, map)
} else {
that.$Toast('您选择的地址没有解析到结果!')
}
},
that.city
)
}
},
createdMarker(point, map) {
map.centerAndZoom(point, 16)
let marker = new BMap.Marker(point)
map.addOverlay(marker)
this.customInfoBox(map, marker)
},
navigation() {
if (isQZD()) {
callApp('mapNavigationAction', {
title: this.company,
desc: this.address,
latitude: this.point.lat,
longitude: this.point.lng
})
} else {
this.$Toast('非企知道应用')
}
},
copyText() {
const el = document.createElement('textarea')
el.value = this.address
el.setAttribute('readonly', '')
el.style.cssText = `position:fixed;left:-9999px`
document.body.appendChild(el)
const selected = document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false
el.select()
document.execCommand('copy')
document.body.removeChild(el)
if (selected) {
document.getSelection().removeAllRanges()
document.getSelection().addRange(selected)
}
this.$toast('复制成功')
},
getHtml() {
const html = `<div class="box-content">
<div class="box-content-left">
<span class="address-text double-line-ellipsis">${this.address}</span>
</div>
<div class="box-content-right" >
<button class="btn" id="btn">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="0.3rem" height="0.3rem" viewBox="0 0 30 31" version="1.1">
<title>导航icon</title>
<g id="月底" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1.2地址详情页备份" transform="translate(-567.000000, -745.000000)" fill="#FFFFFF" fill-rule="nonzero">
<g id="编组-2" transform="translate(25.000000, 697.538462)">
<g id="编组" transform="translate(500.000000, 18.500000)">
<g id="导航icon" transform="translate(42.000000, 29.000000)">
<path d="M4.89231976,10.7884564 L25.2131095,2.05686699 C26.2279586,1.62079905 27.4041592,2.08999383 27.8402271,3.10484285 C28.0639952,3.62561229 28.0562853,4.21687246 27.8190143,4.73163008 L18.5776304,24.780734 C18.1152486,25.7838675 16.9272137,26.2222333 15.9240802,25.7598515 C15.369156,25.5040661 14.9616056,25.008637 14.8176179,24.4148066 L13.3099188,18.1967912 C13.1460879,17.521124 12.6431229,16.9790163 11.981604,16.7651017 L5.06652675,14.5289816 C4.01554072,14.1891255 3.43905599,13.0616252 3.77891207,12.0106392 C3.95641149,11.4617321 4.36228623,11.0162051 4.89231976,10.7884564 Z" id="路径"/>
</g>
</g>
</g>
</g>
</g>
</svg>
<span class="btn-txt">导航</span>
</button>
</div>
</div>`
return html
},
async customCopyModal(addDom) {
const div = document.createElement('div')
div.className = 'copy-box'
const span = document.createElement('span')
span.className = 'copy-text'
span.textContent = '复制'
BMapLib.EventWrapper.addDomListener(
div,
'touchend',
() => {
this.copyText()
addDom.style.background = `#fff`
addDom.removeChild(div)
},
false
)
div.appendChild(span)
addDom.insertBefore(div, null)
},
async customInfoBox(map, marker) {
let infoBox = new BMapLib.InfoBox(map, this.getHtml(), {
boxStyle: {
background: '#fff',
width: '7rem',
borderRadius: '0.16rem',
boxShadow: '0 2px 4px 0 rgba(0,0,0,0.2)',
zIndex: 999,
padding: '0.4rem 0.2rem',
align: INFOBOX_AT_TOP
},
// 隐藏关闭按钮
closeIconMargin: '1px -50px 0 0',
closeIconUrl: closeImage,
enableAutoPan: true,
offset: new BMap.Size(0, 17)
})
if (this.lastInfoBox && this.lastInfoBox !== null) {
this.lastInfoBox.close()
this.lastInfoBox = null
} else {
infoBox.open(marker)
this.lastInfoBox = infoBox
await this.$nextTick()
this.handleDom()
}
},
/**
*绑定导航事件&长按复制
*/
handleDom() {
const btn = document.querySelector('#btn')
if (btn && btn !== null) {
// 绑定导航事件
BMapLib.EventWrapper.addDomListener(btn, 'touchend', () => {
this.navigation()
})
}
const addressDom = document.querySelector('.address-text')
if (addressDom && addressDom !== null) {
// 地址长按
BMapLib.EventWrapper.addDomListener(
addressDom,
'touchstart',
() => {
clearTimeout(this.loop)
this.loop = setTimeout(() => {
addressDom.style.background = `#EBF2FD`
this.customCopyModal(addressDom)
}, 1000)
},
false
)
BMapLib.EventWrapper.addDomListener(
addressDom,
'touchend',
() => {
clearTimeout(this.loop)
},
false
)
}
}
}
}
</script>
<style lang="scss">
#allmap {
.infoBox:before {
content: '';
width: 0;
height: 0;
border-top: 0.25rem solid #fff;
border-left: 0.25rem solid transparent;
border-right: 0.25rem solid transparent;
position: absolute;
top: 1.62rem;
left: 3.28rem;
}
.box-content {
display: flex;
justify-content: space-between;
&-left {
position: relative;
display: flex;
align-items: center;
.copy-box {
background: #292a2d;
box-shadow: 0px 8px 16px 0px rgba(68, 77, 164, 0.06);
width: 0.88rem;
height: 0.7rem;
position: absolute;
top: -0.7rem;
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: center;
align-items: center;
border-radius: 0.1rem;
font-size: 0.28rem;
&:before {
content: '';
width: 0;
height: 0;
border-top: 0.15rem solid #292a2d;
border-left: 0.15rem solid transparent;
border-right: 0.15rem solid transparent;
position: absolute;
top: 0.66rem;
left: 0.3rem;
}
.copy-text {
color: #fff;
}
}
.address-text {
display: -webkit-box;
width: 4.56rem;
font-size: 0.32rem;
color: #292a2d;
padding: 2px 0.1rem;
}
}
&-right {
z-index: 9999;
.btn {
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
width: 1.8rem;
height: 0.82rem;
line-height: 0.82rem;
background: #3981f4;
border-radius: 9px;
text-align: center;
color: #fff;
.btn-txt {
margin-left: 0.1rem;
font-size: 0.28rem;
}
}
}
}
}
</style>