如何在vue中使用百度地圖添加自定義覆蓋物(水波紋)
簡(jiǎn)介
一如既往,我來給大家分享一個(gè)項(xiàng)目中遇到的比較有意思的需求并介紹一下相應(yīng)的實(shí)現(xiàn)過程。
話不多說,直接上圖:

具體的應(yīng)用場(chǎng)景簡(jiǎn)而言之就是需要我們?cè)诘貓D上添加如圖中所示的自定義覆蓋物。實(shí)現(xiàn)的過程作者分為以下兩點(diǎn)給大家介紹介紹。
- 水波紋的實(shí)現(xiàn)
- 自定義覆蓋物的實(shí)現(xiàn)
水波紋的實(shí)現(xiàn)
這個(gè)需求的實(shí)現(xiàn)肯定是離不開我們自己寫自定義覆蓋物的,那么首先我們來討論一下水波紋動(dòng)畫的實(shí)現(xiàn)。
首先我們可以看到圖中的覆蓋物是由一個(gè)紅心和水波紋組成,其中紅心是固定不動(dòng)的,那么我們可以直接這么寫:
<div class="radar"></div>
.radar {
width: 40px;
height: 40px;
border-radius: 50%;
background-color: red;
}

這樣子我們首先就實(shí)現(xiàn)了紅心部分的樣式。那么水波紋又是怎么實(shí)現(xiàn)的呢?
我們可以從圖中觀察得出先后總共有三個(gè)水波紋從里到外逐漸的往外擴(kuò)散。我們單獨(dú)從一個(gè)水波紋來看的話,其實(shí)往外擴(kuò)散的原理是通過動(dòng)畫讓水波紋的寬高逐漸遞增到一定程度即可,具體擴(kuò)散多大呢讀者可以根據(jù)自己的需求設(shè)定水波紋的最后寬高。
水波紋的基本結(jié)構(gòu)和樣式實(shí)現(xiàn)如下:
<div class="radar"> <div class="ripple"></div> <div class="ripple"></div> <div class="ripple"></div> </div>
.radar {
width: 40px;
height: 40px;
border-radius: 50%;
background-color: red;
position: relative;
.ripple {
width: 40px;
height: 40px;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
border: 1px solid red;
animation: ripple 2s linear infinite;
}
}
之所以將水波紋的dom節(jié)點(diǎn)嵌套在radar節(jié)點(diǎn)里面主要是做一個(gè)“子絕父相”定位以達(dá)到水波紋居中對(duì)齊的效果,這個(gè)應(yīng)該很容易理解。至于水波紋的初始寬高呢,為了方便動(dòng)畫延遲時(shí)間的計(jì)算,我就設(shè)置為跟紅心寬高相等即可,如果讀者有興趣可以嘗試一下寬高設(shè)置在0~40px任意值的看看效果(作者盲猜動(dòng)畫可能會(huì)有點(diǎn)瑕疵,可能也不會(huì)------>“手動(dòng)狗頭”))。
至于動(dòng)畫的實(shí)現(xiàn)呢,這個(gè)就很簡(jiǎn)單了,我們只需要同時(shí)將水波紋的寬高都逐漸變大即可,但是有個(gè)點(diǎn)要注意一下就是水波紋最后是會(huì)消失的,這里我們利用opacity:0配合動(dòng)畫達(dá)到逐漸消失的效果。
@keyframes ripple {
to {
width: 150px;
height: 150px;
opacity: 0;
}
}
代碼到了這里,我們水波紋已經(jīng)是實(shí)現(xiàn)了,但是不是少了點(diǎn)什么?說好的三個(gè)水波紋呢?
這個(gè)問題也很好解決,我們只需要給水波紋設(shè)置對(duì)應(yīng)的動(dòng)畫延遲即可。
.radar :nth-child(1) {
animation-delay: 0.666s;
}
.radar :nth-child(2) {
animation-delay: 1.322s;
}
這樣子我們就把水波紋給實(shí)現(xiàn)出來啦。

自定義覆蓋物的實(shí)現(xiàn)
本次作者采用的是百度地圖實(shí)現(xiàn)的需求,那么如何通過百度地圖來實(shí)現(xiàn)自定義覆蓋物呢?
其實(shí)百度地圖開發(fā)文檔中也很直白的向我們展示自定義覆蓋物的開箱方法。這里作者用es6的class稍微改寫了一下寫法,道理都一樣的,官方案例可以參考百度地圖demo
自定義覆蓋物實(shí)現(xiàn)分以下三步:
- 定義構(gòu)造函數(shù)并繼承Overlay
- 初始化自定義覆蓋物
- 繪制覆蓋物
定義構(gòu)造函數(shù)并繼承Overlay
按照官網(wǎng)的說法是:“首先您需要定義自定義覆蓋物的構(gòu)造函數(shù),通過構(gòu)造函數(shù)參數(shù)可以傳遞一些自由的變量。設(shè)置自定義覆蓋物對(duì)象的prototype屬性為Overlay的實(shí)例,以便繼承覆蓋物基類”。
運(yùn)用es6 class我們可以很快的實(shí)現(xiàn):
其中point傳遞的是坐標(biāo)位置,用于后續(xù)計(jì)算覆蓋物在地圖上的位置。
class RadarOverlay extends BMap.Overlay {
constructor(point) {
super();
this.point = point;
}
}
初始化自定義覆蓋物
官方的說法是:“實(shí)現(xiàn)initialize方法,當(dāng)調(diào)用map.addOverlay方法時(shí),API會(huì)調(diào)用此方法。當(dāng)調(diào)用map.addOverlay方法添加自定義覆蓋物時(shí),API會(huì)調(diào)用該對(duì)象的initialize方法用來初始化覆蓋物,在初始化過程中需要?jiǎng)?chuàng)建覆蓋物所需要的DOM元素,并添加到地圖相應(yīng)的容器中。這里我們選擇添加在容器markerPane上?!?/p>
其實(shí)意思大概就是說,因?yàn)榘俣鹊貓D在添加overLay時(shí)會(huì)調(diào)用自定義覆蓋物構(gòu)造函數(shù)中的initialize方法,這個(gè)initialize方法是用來初始化覆蓋物的,他會(huì)在初始化過程中創(chuàng)建所需要的DOM,因此我們要在我們自己的構(gòu)造函數(shù)(這里我們用的是類)中實(shí)現(xiàn)一個(gè)initialize。
百度地圖官網(wǎng)的方法:

那么我們就按照官網(wǎng)的要求,在類中定義一個(gè)initialize方法。其中template存的是我們初始化中所需要的DOM元素,這里的dom節(jié)點(diǎn)會(huì)比上文中實(shí)現(xiàn)水波紋的環(huán)節(jié)多了一個(gè)className為rader-box的父節(jié)點(diǎn),因?yàn)樵诠倬W(wǎng)中我們也可以看到官方實(shí)例在創(chuàng)建DOM元素時(shí)給DOM節(jié)點(diǎn)添加了position:absolute的樣式,但由于我們的radar節(jié)點(diǎn)的position為relative,所以我們需要在最外層多嵌套一層dom節(jié)點(diǎn)以確保整個(gè)dom相對(duì)于地圖定位。當(dāng)然啦該父節(jié)點(diǎn)的position也就為絕對(duì)定位
initialize(map) {
this._map = map;
const template = `<div class="radar-box">
<div class="radar">
<div class="ripple"></div>
<div class="ripple"></div>
<div class="ripple"></div>
</div>
</div>`;
// 創(chuàng)建文檔碎片
const divFragment = document.createRange().createContextualFragment(template);
const div = divFragment.querySelectorAll('.radar-box')[0];
// 將div添加到覆蓋物容器中
map.getPanes().markerPane.appendChild(div);
this._div = div;
return div;
}
這樣子我們就成功的在類中定義了一個(gè)initialize方法,至于為什么要將div添加到覆蓋物容器中官網(wǎng)的也有如下說明:
大概就是說百度地圖里面已經(jīng)給我們提供了若干的覆蓋物展示方法,我們自定義的覆蓋物其實(shí)是保存在我們選擇的其中某個(gè)覆蓋物容器之下,有興趣的小伙伴可以去了解一下各種覆蓋物容器。。。
繪制覆蓋物
這里作者繼續(xù)拋磚引玉阿,官方的說法是:“到目前為止,我們僅僅把覆蓋物添加到了地圖上,但是并沒有將它放置在正確的位置上。您需要在draw方法中設(shè)置覆蓋物的位置,每當(dāng)?shù)貓D狀態(tài)發(fā)生變化(比如:位置移動(dòng)、級(jí)別變化)時(shí),API都會(huì)調(diào)用覆蓋物的draw方法,用于重新計(jì)算覆蓋物的位置。通過map.pointToOverlayPixel方法可以將地理坐標(biāo)轉(zhuǎn)換到覆蓋物的所需要的像素坐標(biāo)?!?/p>
簡(jiǎn)單來講就是比如地圖縮放比例之后,會(huì)重新調(diào)用覆蓋物中的draw方法,用于重新雞算覆蓋物的位置。
那么問題來了,draw方法哪里來的?
所以官方的意思是我們?cè)谧远x覆蓋物中的構(gòu)造函數(shù)定義一個(gè)draw方法,方法中我們利用百度地圖的map.pointToOverlayPixel方法(用來將地理坐標(biāo)轉(zhuǎn)換為像素坐標(biāo))可以將地理坐標(biāo)轉(zhuǎn)換到覆蓋物的所需要的像素坐標(biāo)。
那么我們只需要在類中加入draw方法即可:
其中this.point就是我們構(gòu)造函數(shù)中的point坐標(biāo)點(diǎn),40表示的是我們整個(gè)水波紋的初始寬高,讀者其實(shí)可以將40改為可以傳參的形式比如this.size,這樣會(huì)方便后續(xù)代碼的維護(hù),這里為了直觀的讓讀者理解就不講太復(fù)雜了。
draw() {
// 根據(jù)地理坐標(biāo)轉(zhuǎn)換為像素坐標(biāo),并設(shè)置給容器
const position = this._map.pointToOverlayPixel(this.point);
this._div.style.left = `${position.x - 40 / 2}px`;
this._div.style.top = `${position.y - 40 / 2}px`;
}
到此,我們整個(gè)自定義覆蓋物的類就已經(jīng)實(shí)現(xiàn)了,整體代碼圖下(這里把40改為this.size代碼維護(hù)起來稍微方便點(diǎn)):
class RadarOverlay extends BMap.Overlay {
constructor(point, size) {
super();
this.point = point;
this.size = size;
}
initialize(map) {
this._map = map;
const template = `<div class="radar-box">
<div class="radar">
<div class="ripple"></div>
<div class="ripple"></div>
<div class="ripple"></div>
</div>
</div>`;
const divFragment = document.createRange().createContextualFragment(template);
const div = divFragment.querySelectorAll('.radar-box')[0];
map.getPanes().markerPane.appendChild(div);
this._div = div;
return div;
}
draw() {
// 根據(jù)地理坐標(biāo)轉(zhuǎn)換為像素坐標(biāo),并設(shè)置給容器
const position = this._map.pointToOverlayPixel(this.point);
this._div.style.left = `${position.x - this.size / 2}px`;
this._div.style.top = `${position.y - this.size / 2}px`;
}
}
自定義覆蓋物的使用
那既然我們都已經(jīng)實(shí)現(xiàn)了自定義的覆蓋物,第一件事當(dāng)然就是把它給使用上,具體如下:
initMap() {
const map = new BMap.Map(this.$refs.map);
map.centerAndZoom(new BMap.Point(116.404, 39.915), 15);
// 實(shí)例化我們要繪制自定義覆蓋物的點(diǎn)坐標(biāo)
const point = new BMap.Point(116.404, 39.915);
// 實(shí)例化自定義覆蓋物,將坐標(biāo)點(diǎn)和水波紋的尺寸傳進(jìn)構(gòu)造函數(shù)中
const radar = new RadarOverlay(point, 40);
// 添加自定義覆蓋物
map.addOverlay(radar);
}
效果如圖:

結(jié)語
至于構(gòu)造自定義覆蓋物的其他內(nèi)容,大佬們?nèi)绻钊氲脑捒梢詤⒖及俣鹊貓D的文檔,里面講的肯定要比作者更加詳細(xì)(狗頭)。如果文章的內(nèi)容有問題話的歡迎留言點(diǎn)出,希望能與各路大佬們交流交流,喜歡作者的文章的話也別忘了給我點(diǎn)個(gè)贊,這對(duì)我來說很重要。
源碼地址:https://gitee.com/zhao_jiahao/baidu-map-custom-cover
到此這篇關(guān)于如何在vue中使用百度地圖添加自定義覆蓋物(水波紋)的文章就介紹到這了,更多相關(guān)vue用百度地圖添加自定義覆蓋物內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue使用自定義事件的表單輸入組件用法詳解【日期組件與貨幣組件】
這篇文章主要介紹了vue使用自定義事件的表單輸入組件用法,結(jié)合實(shí)例形式詳細(xì)分析了vue.js日期組件與貨幣組件相關(guān)操作技巧及注意事項(xiàng),需要的朋友可以參考下2020-06-06
vuejs實(shí)現(xiàn)標(biāo)簽選項(xiàng)卡動(dòng)態(tài)更改css樣式的方法
這篇文章主要介紹了vuejs實(shí)現(xiàn)標(biāo)簽選項(xiàng)卡-動(dòng)態(tài)更改css樣式的方法,代碼分為html和js兩部分,需要的朋友可以參考下2018-05-05
詳解vue的數(shù)據(jù)劫持以及操作數(shù)組的坑
這篇文章主要介紹了vue的數(shù)據(jù)劫持以及操作數(shù)組的坑,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
Vue項(xiàng)目的表單校驗(yàn)實(shí)戰(zhàn)指南
這篇文章主要介紹了Vue項(xiàng)目表單校驗(yàn)的相關(guān)資料,前端表單校驗(yàn)?zāi)軠p少無效請(qǐng)求,保護(hù)后端接口,使用ElementPlus表單組件進(jìn)行校驗(yàn),需要準(zhǔn)備表單對(duì)象、規(guī)則對(duì)象并進(jìn)行雙向綁定,用戶名、密碼以及協(xié)議勾選等字段都需符合特定規(guī)則,需要的朋友可以參考下2024-10-10
Ant Design Vue table中列超長(zhǎng)顯示...并加提示語的實(shí)例
這篇文章主要介紹了Ant Design Vue table中列超長(zhǎng)顯示...并加提示語的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-10-10
Vue實(shí)現(xiàn)移動(dòng)端頁(yè)面切換效果【推薦】
這篇文章主要介紹了Vue實(shí)現(xiàn)移動(dòng)端頁(yè)面切換效果,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-11-11
Vue.js遞歸組件實(shí)現(xiàn)組織架構(gòu)樹和選人功能
這篇文章主要介紹了Vue.js遞歸組件實(shí)現(xiàn)組織架構(gòu)樹和選人功能,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07

