在 Vue3 + TypeScript 項目中,為了采用 標(biāo)簽組件 的方式,使用百度地圖組件,沖浪發(fā)現(xiàn)了一個開源庫 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
目錄
快速上手
全局注冊
局部注冊
注意事項
錯誤示例
正確示例
輸入框搜索點位,并定位至該點位
實現(xiàn)效果
引入地圖組件
為什么不采用 BmAutoComplete?
使用 BmControl 實現(xiàn)自定義控件
定義響應(yīng)式變量
關(guān)于初始化變量的踩坑
添加地圖初始化方法 ready
監(jiān)聽外部組件傳入地址的監(jiān)變化
ready 方法邏輯?
獲取地址搜索結(jié)果列表
使用百度地圖 API 檢索跨域
獲取搜索結(jié)果列表方法?
執(zhí)行定位
使用 nextTick 修改數(shù)據(jù)
點位彈窗信息
展示搜索點位的周邊點位彈窗
實現(xiàn)效果
引入地圖組件
輻射圓、海量點組件
控制彈框在地圖范圍內(nèi)顯示
接收彈框組件的周邊點位數(shù)據(jù),并顯示
【一個我很迷惑的報錯】多個頁面引用地圖組件時,路由報錯
快速上手
全局注冊
一次性引入 百度地圖組件庫 的所有組件
import { createApp } from 'vue'
import App from './App.vue'
import BaiduMap from 'vue-baidu-map-3x'
const app = createApp(App);
app.use(BaiduMap, {
// ak 是在百度地圖開發(fā)者平臺申請的密鑰 詳見 http://lbsyun.baidu.com/apiconsole/key */
ak: '百度地圖ak',
// v:'2.0', // 默認(rèn)使用3.0
// type: 'WebGL' // ||API 默認(rèn)API (使用此模式 BMap=BMapGL)
});
app.mount('#app');
局部注冊
<template>
<baidu-map class="map" ak="BaiduMapAK" v="3.0" type="API" :center="{lng: 116.404, lat: 39.915}" :zoom="15">
</baidu-map>
</template>
<script setup>
import { BaiduMap } from 'vue-baidu-map-3x'
</script>
<style>
.map {
width: 100%;
height: 300px;
}
</style>
注意事項
- 百度地圖容器 必須 定義高度:BaiduMap?組件容器本身是一個空的塊級元素,如果容器不定義高度,百度地圖將渲染在一個高度為?0?不可見的容器內(nèi)
- 百度地圖容器 必須 定義 center、zoom:沒有設(shè)置?center?和?zoom?屬性的地圖組件是不進行地圖渲染的。當(dāng) center?屬性為合法地名字符串時例外,因為百度地圖會根據(jù)地名自動調(diào)整?zoom?的值
- 在 ready 中執(zhí)行地圖 API 加載后的代碼,不能在 onMounted 中執(zhí)行:由于百度地圖?JS?API?只有?JSONP?一種加載方式,因此?BaiduMap?組件及其所有子組件的渲染只能是異步的。因此,請使用在組件的?ready?事件來執(zhí)行地圖?API?加載完畢后才能執(zhí)行的代碼,不要試圖在?vue?自身的生命周期中調(diào)用?BMap?類,更不要在這些時機修改?model?層
錯誤示例
<script setup>
import {ref,onMounted} from 'vue';
const center = ref({lng: 0, lat: 0});
const zoom = ref(3);
onMounted(() => {
center.value.lng = 116.404;
center.value.lat = 39.915;
zoom.value = 15;
});
</script>
正確示例
<script setup>
import {ref,onMounted} from 'vue';
const center = ref({lng: 0, lat: 0});
const zoom = ref(3);
const handler = ({BMap, map}) => {
console.log(BMap, map);
center.value.lng = 116.404;
center.value.lat = 39.915;
zoom.value = 15;
}
</script>
輸入框搜索點位,并定位至該點位
實現(xiàn)效果
二次封裝地圖組件:
- 該組件可以被 編輯、查看、其他頁面 進行引入
- 該組件可以接收指定的值(地點名稱、經(jīng)緯度等等)
- 點擊 確認(rèn)按鈕 后,搜索顯示結(jié)果列表
- 點擊 結(jié)果列表的某項 后,定位到該點,并讓該點居中展示
接收搜索字段,顯示搜索結(jié)果列表:
點擊結(jié)果列表,執(zhí)行定位,展示點位信息:
引入地圖組件
先來看看完整代碼
<baidu-map
class="ths-map"
:zoom="mapZoom"
:center="mapCenter"
@ready="ready"
>
<!-- 比例尺控件 -->
<bm-scale anchor="BMAP_ANCHOR_TOP_RIGHT"></bm-scale>
<!-- 縮放控件 -->
<bm-navigation anchor="BMAP_ANCHOR_TOP_RIGHT"></bm-navigation>
<!-- 定位控件 -->
<bm-geolocation anchor="BMAP_ANCHOR_BOTTOM_RIGHT" :show-address-bar="true" :auto-location="true"></bm-geolocation>
<!-- 自定義控件 -->
<bm-control class="map-search-bm-control">
<!-- 手寫輸入框 -->
<div class="flex map-search-container">
<el-input v-model="keyword" class="map-search-input" @input="getSearchList"></el-input>
<el-button type="primary" class="map-search-btn" @click="getSearchList">
搜索
</el-button>
</div>
<!-- 搜索列表 -->
<div v-if="searchListVisible" class="map-search-list">
<div
v-for="(elem, eIndex) of searchList"
:key="eIndex"
class="map-search-item"
@click="performPositioning(elem)"
>
<p class="map-search-item-title">
{{ elem.name }}
</p>
<p class="map-search-item-addr">
{{ elem.address }}
</p>
</div>
</div>
</bm-control>
<!-- 點 https://map.heifahaizei.com/doc/overlay/marker.html -->
<bm-marker
v-if="isShowSearchPoint"
:position="{ lng: searchPoint.location.lng, lat: searchPoint.location.lat }"
@click="spInfoWindow.show = true"
>
</bm-marker>
<!-- 搜索點位彈窗 https://map.heifahaizei.com/doc/overlay/info-window.html#%E5%B1%9E%E6%80%A7 -->
<bm-info-window
:show="spInfoWindow.show"
:title="spInfoWindow.name"
:offset="{ width: 0, height: -24 }"
:position="{ lng: spInfoWindow.location.lng, lat: spInfoWindow.location.lat }"
:width="0"
:max-width="300"
@close="spInfoWindow.show = false"
@open="spInfoWindow.show = true"
>
<!-- {{ spInfoWindow }} -->
<!-- 搜索點位地址 -->
<p class="sp-info-window-addr">
{{ spInfoWindow.spName }}:<br />
{{ spInfoWindow.spAddress }}
</p>
<div class="sp-info-window-header">
<!-- 搜索點位名稱 -->
<!-- <span class="sp-info-window-name">{{ spInfoWindow.spName }}</span> -->
<span class="sp-info-window-around" @click="infoWinGoAround"> 搜周邊 </span>
</div>
</bm-info-window>
</baidu-map>
?文章來源地址http://www.zghlxwxcb.cn/news/detail-635123.html
為什么不采用 BmAutoComplete?
這個需求使用 官網(wǎng)組件?bm-auto-complete 能實現(xiàn),不采用是基于以下幾個原因:
- UI 定制效果太差了,無法 深度定制 輸入框樣式(使用?el-input 組件會出現(xiàn) bug,貌似只能采用原生 input 組件)
- 控制 請求發(fā)送時機 不方便(文字發(fā)生變化直接就請求了,有的時候希望點了確認(rèn)按鈕再請求)
- 無法自定義請求結(jié)果列表
使用 BmControl 實現(xiàn)自定義控件
為了解決上一個問題,采用了 BmControl
定義響應(yīng)式變量
關(guān)于初始化變量的踩坑
這些變量 盡量 一開始就寫好數(shù)據(jù)結(jié)構(gòu):
- 比如 mapCenter 里,一開始就應(yīng)該定義 lng、lat,后面具體的值可以是 0 state.mapCenter = { lng: 0, lat: 0}
- 如果直接初始化成 state.mapCenter = {},會導(dǎo)致發(fā)生不可預(yù)知的錯誤
當(dāng)然這并不是絕對的:
- 我最開始沒初始化 單個點位 searchPoint 的對象結(jié)構(gòu)時,沒報錯
- 我最開始沒初始化 點位信息彈窗 spInfoWindow 的對象結(jié)構(gòu)時,就報錯找不到 lng 屬性了
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,
// 搜索關(guān)鍵字
keyword: '',
// 搜索列表
searchList: [] as any[],
// 搜索列表是否可見
searchListVisible: false,
});
初始化方法可以在 ready 函數(shù)中執(zhí)行,不能在 onMounted 中執(zhí)行
/**
* 頁面初始化
*/
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;
};
添加地圖初始化方法 ready
監(jiān)聽外部組件傳入地址的監(jiān)變化
外部傳入的地址,會被賦值給 state 中的變量,防止 props 被修改
watch(
() => props.complaintsAddr,
() => {
state.keyword = props.complaintsAddr;
// 關(guān)閉周邊搜索彈框
state.aroundDialogVisible = false;
},
);
ready 方法邏輯?
props.complaintsAddr 是供其他頁面?zhèn)魅?地址 的字段:
- 如果接收到了這個字段,則直接調(diào)用百度地圖 API 接口,獲取搜索結(jié)果列表,執(zhí)行定位
- 如果沒接收到這個字段,則執(zhí)行初始化,調(diào)整 state 中的變量,隱藏不該出現(xiàn)的內(nèi)容
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();
*/
});
?
獲取地址搜索結(jié)果列表
使用百度地圖 API 檢索跨域
?地點檢索 | 百度地圖API SDK
本地調(diào)用百度接口,會出現(xiàn)跨域問題,這是正常的,使用 nginx 代理本地發(fā)送的請求
location /mapapi/ {
proxy_pass http://api.map.baidu.com/;
add_header Access-Control-Allow-Origin *;
}
?
獲取搜索結(jié)果列表方法?
/**
* 獲取搜索列表
*/
const getSearchList = async () => {
state.searchList = [];
try {
const res = await getInputList(state.keyword, '寶安區(qū)');
if (res.data.message === 'ok') {
state.searchList = res.data?.results;
// 展示搜索列表
state.searchListVisible = true;
}
} catch (err) {
console.error('地圖 搜索列表 接口請求失敗', err);
state.searchList = [];
state.searchListVisible = true;
}
};
執(zhí)行定位
使用 nextTick 修改數(shù)據(jù)
單個點 BmMaker 組件,使用 v-if 進行控制,否則一開始沒點搜索結(jié)果的時候,就會直接渲染
使用 nextTick,修改點位坐標(biāo)數(shù)據(jù)、中心點數(shù)據(jù)、點位彈框信息,原因如下:
- 如果不使用 nextTick,會導(dǎo)致 點位彈框信息 報錯 —— 獲取不到 img 這個 DOM 元素
- 也就是說,點位彈框信息 必須在 點位存在 的時候,才能渲染
選擇結(jié)果列表后,應(yīng)該把選中的結(jié)果信息發(fā)出去,告訴外面使用地圖的組件
/**
* 執(zhí)行定位
* @param elem 點位信息,必傳
* @param isCloseSearchList 是否關(guān)閉搜索列表,菲必傳
*/
const performPositioning = async (elem: any) => {
// console.log('執(zhí)行定位 ---', elem);
// 隱藏列表
state.searchListVisible = false;
// 修改關(guān)鍵字信息
state.keyword = elem.address ? elem.address : elem.name;
// 更新外部組件的關(guān)鍵字信息
emit('search-point-info', elem);
// 渲染點位
nextTick(() => {
// 修改中心點坐標(biāo),把當(dāng)前搜索點,設(shè)置為中心點
state.mapCenter.lng = elem.location.lng;
state.mapCenter.lat = elem.location.lat;
// 修改搜索點位坐標(biāo)
state.searchPoint = elem;
// 展示搜索點位
state.isShowSearchPoint = true;
console.log('搜索點位的經(jīng)緯度 ---', state.searchPoint);
// 設(shè)置點位彈窗信息
showInfoWindow(elem);
});
};
?
點位彈窗信息
/**
* 展示點位彈窗
* @param elem 點位信息
*/
const showInfoWindow = (elem: any) => {
// 設(shè)置點位彈窗信息
state.spInfoWindow.spName = elem.name; // 標(biāo)題
state.spInfoWindow.spAddress = elem.address; // 地址
state.spInfoWindow.location = elem.location; // 彈框坐標(biāo)
// 展示點位信息彈框
state.spInfoWindow.show = true;
// 修改搜索點位坐標(biāo)
state.searchPoint = elem;
state.mapCenter = elem.location;
console.log('展示點位彈窗 ---', state.spInfoWindow);
};
展示搜索點位的周邊點位彈窗
實現(xiàn)效果
- 點擊搜索點位的去周邊后,出現(xiàn)彈框
- 彈窗只能在地圖中顯示,不能在整個屏幕中顯示
- 搜索到周邊點位后,地圖繪制周邊距離(輻射圓),并把所有點位進行打點
?
?
引入地圖組件
輻射圓、海量點組件
<!-- 添加-多個點 https://map.heifahaizei.com/doc/overlay/point-collection.html -->
<bm-point-collection
:points="points"
shape="BMAP_POINT_SHAPE_STAR"
color="red"
size="BMAP_POINT_SIZE_SMALL"
>
</bm-point-collection>
<!-- 圓 https://map.heifahaizei.com/doc/overlay/circle.html -->
<bm-circle
:center="circlePath.center"
:radius="circlePath.radius"
stroke-color="blue"
:stroke-opacity="0.5"
:stroke-weight="2"
:editing="false"
:mass-clear="true"
></bm-circle>
?
控制彈框在地圖范圍內(nèi)顯示
el-dialog 只能在全局內(nèi)顯示,所以:手寫?div 當(dāng)彈框,讓彈框跟地圖點位同級,通過絕對定位實現(xiàn)
接收彈框組件的周邊點位數(shù)據(jù),并顯示
注意:輻射圓單位是 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;
// 填充輻射圓中心坐標(biāo)
state.circlePath.center = elems.location;
};
?
【一個我很迷惑的報錯】多個頁面引用地圖組件時,路由報錯
我在查看、編輯頁都引用了地圖組件,就會出現(xiàn)下面的報錯
后來發(fā)現(xiàn),只要我把地圖、地圖組件內(nèi)部的組件,再 cv 一份出來,分別引入到對應(yīng)的頁面,才能解決報錯
如下所示,3 中的 edit、view 會引用地圖組件,如果 3 中的 edit、view 同時引用了 1 或者同時引用了 2,那就會報錯
3 中的 edit 引用 1,view 引用 2,就不會報錯
文章來源:http://www.zghlxwxcb.cn/news/detail-635123.html
?
到了這里,關(guān)于vue-baidu-map-3x 使用記錄的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!