在 Vue3 + TypeScript 项目中,为了采用 标签组件 的方式,使用百度地图组件,冲浪发现了一个开源库 ovo,很方便!喜欢的朋友记得帮 原作者 点下 star ~
vue-baidu-map-3xbaidu-map的vue3/vue2版本(支持v2.0、v3.0和webGl api)我全都有。同时也是vue2-baidu-map的文档https://map.heifahaizei.com/doc/index.html
目录
快速上手
全局注册
局部注册
注意事项
错误示例
正确示例
输入框搜索点位,并定位至该点位
实现效果
引入地图组件
为什么不采用 BmAutoComplete?
使用 BmControl 实现自定义控件
定义响应式变量
关于初始化变量的踩坑
添加地图初始化方法 ready
监听外部组件传入地址的监变化
ready 方法逻辑
获取地址搜索结果列表
使用百度地图 API 检索跨域
获取搜索结果列表方法
执行定位
使用 nextTick 修改数据
点位弹窗信息
展示搜索点位的周边点位弹窗
实现效果
引入地图组件
辐射圆、海量点组件
控制弹框在地图范围内显示
接收弹框组件的周边点位数据,并显示
【一个我很迷惑的报错】多个页面引用地图组件时,路由报错
一次性引入 百度地图组件库 的所有组件
import { createApp } from 'vue'
import App from './App.vue'
import BaiduMap from 'vue-baidu-map-3x'
const app = createApp(App);
app.use(BaiduMap, {
// ak 是在百度地图开发者平台申请的密钥 详见 http://lbsyun.baidu.com/apiconsole/key */
ak: '百度地图ak',
// v:'2.0', // 默认使用3.0
// type: 'WebGL' // ||API 默认API (使用此模式 BMap=BMapGL)
});
app.mount('#app');
二次封装地图组件:
接收搜索字段,显示搜索结果列表:
先来看看完整代码
搜索
{{ elem.name }}
{{ elem.address }}
{{ spInfoWindow.spName }}:
{{ spInfoWindow.spAddress }}
搜周边
这个需求使用 官网组件 bm-auto-complete 能实现,不采用是基于以下几个原因:
为了解决上一个问题,采用了 BmControl
这些变量 尽量 一开始就写好数据结构:
当然这并不是绝对的:
const state = reactive({
// 地图缩放级别
mapZoom: 11,
// 地图中心点
mapCenter: {
lng: 113.88402,
lat: 22.555259,
},
// 是否展示搜索点位
isShowSearchPoint: false,
// 搜索点位信息
searchPoint: {
lng: 0,
lat: 0,
} as any,
// 搜索点位弹窗信息
spInfoWindow: {
show: false,
spName: '',
spAddress: '',
location: {
lng: 0,
lat: 0,
},
} as any,
// 搜索关键字
keyword: '',
// 搜索列表
searchList: [] as any[],
// 搜索列表是否可见
searchListVisible: false,
});
初始化方法可以在 ready 函数中执行,不能在 onMounted 中执行
/**
* 页面初始化
*/
const initPage = () => {
// 是否展示搜索点位
state.isShowSearchPoint = false;
// 搜索点位信息
state.searchPoint = {} as any;
// 搜索点位弹窗信息
state.spInfoWindow = {
show: false,
spName: '',
spAddress: '',
location: {
lng: 0,
lat: 0,
},
};
// 搜索列表
state.searchList = [];
// 搜索列表是否可见
state.searchListVisible = false;
};
外部传入的地址,会被赋值给 state 中的变量,防止 props 被修改
watch(
() => props.complaintsAddr,
() => {
state.keyword = props.complaintsAddr;
// 关闭周边搜索弹框
state.aroundDialogVisible = false;
},
);
props.complaintsAddr 是供其他页面传入 地址 的字段:
const ready = async (e: any) => {
if (props.complaintsAddr) {
await getSearchList();
for (const elem of state.searchList) {
if (elem.address === props.complaintsAddr || elem.name === props.complaintsAddr) {
performPositioning(elem);
break;
}
}
} else {
// 页面初始化
await initPage();
}
};
onMounted(async () => {
/*
* 页面初始化
* await initPage();
*/
});
地点检索 | 百度地图API SDK
本地调用百度接口,会出现跨域问题,这是正常的,使用 nginx 代理本地发送的请求
location /mapapi/ {
proxy_pass http://api.map.baidu.com/;
add_header Access-Control-Allow-Origin *;
}
/**
* 获取搜索列表
*/
const getSearchList = async () => {
state.searchList = [];
try {
const res = await getInputList(state.keyword, '宝安区');
if (res.data.message === 'ok') {
state.searchList = res.data?.results;
// 展示搜索列表
state.searchListVisible = true;
}
} catch (err) {
console.error('地图 搜索列表 接口请求失败', err);
state.searchList = [];
state.searchListVisible = true;
}
};
单个点 BmMaker 组件,使用 v-if 进行控制,否则一开始没点搜索结果的时候,就会直接渲染
使用 nextTick,修改点位坐标数据、中心点数据、点位弹框信息,原因如下:
选择结果列表后,应该把选中的结果信息发出去,告诉外面使用地图的组件
/**
* 执行定位
* @param elem 点位信息,必传
* @param isCloseSearchList 是否关闭搜索列表,菲必传
*/
const performPositioning = async (elem: any) => {
// console.log('执行定位 ---', elem);
// 隐藏列表
state.searchListVisible = false;
// 修改关键字信息
state.keyword = elem.address ? elem.address : elem.name;
// 更新外部组件的关键字信息
emit('search-point-info', elem);
// 渲染点位
nextTick(() => {
// 修改中心点坐标,把当前搜索点,设置为中心点
state.mapCenter.lng = elem.location.lng;
state.mapCenter.lat = elem.location.lat;
// 修改搜索点位坐标
state.searchPoint = elem;
// 展示搜索点位
state.isShowSearchPoint = true;
console.log('搜索点位的经纬度 ---', state.searchPoint);
// 设置点位弹窗信息
showInfoWindow(elem);
});
};
/**
* 展示点位弹窗
* @param elem 点位信息
*/
const showInfoWindow = (elem: any) => {
// 设置点位弹窗信息
state.spInfoWindow.spName = elem.name; // 标题
state.spInfoWindow.spAddress = elem.address; // 地址
state.spInfoWindow.location = elem.location; // 弹框坐标
// 展示点位信息弹框
state.spInfoWindow.show = true;
// 修改搜索点位坐标
state.searchPoint = elem;
state.mapCenter = elem.location;
console.log('展示点位弹窗 ---', state.spInfoWindow);
};
el-dialog 只能在全局内显示,所以:手写 div 当弹框,让弹框跟地图点位同级,通过绝对定位实现
注意:辐射圆单位是 m,画太小了,页面就显示不出辐射圆了(……)
/**
* 地图多个点集合
*/
const addPoints = (elems: any) => {
const pointAll = [];
for (const workSite of elems.workSiteResult) {
const position = { lng: workSite.longitude, lat: workSite.latitude };
pointAll.push(position);
}
state.points = pointAll;
// 填充辐射圆半径
state.circlePath.radius = elems.kilometerDistance * 1000;
// 填充辐射圆中心坐标
state.circlePath.center = elems.location;
};
我在查看、编辑页都引用了地图组件,就会出现下面的报错
后来发现,只要我把地图、地图组件内部的组件,再 cv 一份出来,分别引入到对应的页面,才能解决报错
如下所示,3 中的 edit、view 会引用地图组件,如果 3 中的 edit、view 同时引用了 1 或者同时引用了 2,那就会报错
3 中的 edit 引用 1,view 引用 2,就不会报错