Vue開發(fā)高德地圖應用的最佳實踐
前言
之前做不過不少關于地圖交互的產(chǎn)品系統(tǒng),目前國內主流的地圖應用 SDK 只有幾家:高德、百度和騰訊。所以個人覺得在 PC 應用上高德地圖開發(fā)相對好一些,至少體驗起來沒有很明顯的坑。這篇文章算是總結下開發(fā)地圖應用總結吧。
異步加載
因為使用 js sdk 應用,腳本文件本身體積很大,所以要注意下加載的白屏時間,解決用戶體驗問題,目前絕大部分產(chǎn)品應用都是 SPA 單頁面應用系統(tǒng),所以我封裝一個異步加載的方法:
const loadScripts = async scripts => {
const get = src => {
return new Promise(function(resolve, reject) {
const el = document.createElement('script')
el.addEventListener('load', function() {
resolve(src)
}, false)
el.addEventListener('error', function() {
reject(src)
}, false)
el.id = src.id
el.src = src.url
document.getElementsByTagName('body')[0].appendChild(el) || document.getElementsByTagName('head')[0].appendChild(el)
})
}
const myPromises = scripts.map(async script => {
if (document.getElementById(script.id) === null) {
return await get(script)
}
})
return await Promise.all(myPromises)
}
export default loadScripts
這個方法在加載腳本的時候先去判斷頁面是否存在該腳本,如果存在就不會加載第二次,然后再利用加載完畢回調執(zhí)行相關方法。
封裝組件
如果系統(tǒng)中有多個頁面需要地圖應用業(yè)務,那么需要封裝一個通用型的地圖組件,提高項目可維護性,我這邊就簡單的封裝下地圖應用:
<template>
<div
:style="{
width: width,
height: height
}"
class="amap-container"
>
<div ref="amap" class="amap">
<slot />
</div>
</div>
</template>
<style lang="scss" scoped>
.amap-container {
.amap {
width: 100%;
height: 100%;
}
}
</style>
指定一個地圖應用容器,外面包裹一層指定高寬,高寬作為外部變量傳入,業(yè)務邏輯如下:
import loadScripts from '@/loadScripts'
export default {
name: 'AMapContainer',
props: {
width: {
require: false,
type: String,
default: '100%'
},
height: {
require: false,
type: String,
default: '600px'
},
options: {
require: false,
type: Object,
default: () => {}
}
},
data: () => ({
amap: null,
amapInfo: {
key: 'xxxxxxxxxxxxxx'
}
}),
created() {
this.initAMap()
},
beforeDestroy() {
// 銷毀地圖
if (!this.amap) {
return
}
this.amap.destroy()
this.amap = null
},
methods: {
initAMap() {
loadScripts([{
id: 'ampa',
url: `https://webapi.amap.com/maps?v=2.0&key=${this.amapInfo.key}&plugin=AMap.PolygonEditor`
}]).then(() => {
this.amap = new window.AMap.Map(this.$refs['amap'], this.options)
this.$emit('map', this.amap, window.AMap)
})
}
}
}
應用加載的時候初始化地圖容器:異步加載高德地圖 js sdk 然后回調方法里進行實例化地圖應用,并且把地圖實例化的對象傳入 $emit 事件里,方便父類組件需要。另外注意要在銷毀生命周期里對地圖應用進行銷毀,否則會占用大量的系統(tǒng)內存。
使用組件
封裝好組件后就可以在對應的頁面進行引入組件使用即可:
<template>
<amap-container height="100%" :options="amapOptions" @map="getAMapData" />
</template>
<script>
import AMap from '@/components/AMap'
export default {
name: 'AMapDemo',
components: {
'amap-container': AMap
},
data: () => ({
amapOptions: {
zoom: 14,
resizeEnable: true,
viewMode: '3D',
mapStyle: 'amap://styles/normal'
},
AMap: null, // 地圖對象
amap: null // 當前地圖實例
}),
methods: {
/**
* 地圖加載完畢回調
* @param amap
* @param AMap
*/
getAMapData(amap, AMap) {
// 從組件獲取地圖 amap 對象
this.amap = amap
// 從組件獲取地圖 AMap 靜態(tài)對象
this.AMap = AMap
}
}
}
</script>
然后在上面基礎上展開相關業(yè)務。對于地圖應用來說,最核心的數(shù)據(jù)就是地圖應用中的坐標,無論是地圖的標記元素,折線元素(軌跡等),繪制圖元素等,只需要獲取對應的經(jīng)緯度數(shù)據(jù)存到數(shù)據(jù)庫即可,至于怎么獲取這邊不再詳述。
自定義界面最佳實踐
之前制作的地圖應用,在標記的詳細界面(選擇某個標記左鍵打開界面),這個界面是需要傳入原生 document 對象,但是在 vue 對象里面不符合這種寫法,所以導致之前很多系統(tǒng)都是花大量的時間去編寫 dom 結構,甚是頭疼,后續(xù)為了解決這個問題,vue 是否有相關方法掛載組件獲取真實的 document 對象,查閱相關文檔后,確實有這個 api : Vue.extend,利用這個 api 掛載組件對象即可得到實例化組件的對象。
import ContextCard from './components/ContextCard'
// 創(chuàng)建標記
const marker = new this.AMap.Marker({
map: this.amap,
position: [119.058904, 33.537069]
})
// 綁定點擊事件
marker.on('click', this.markerInfoWindow)
// 點擊打開彈窗
const markerInfoWindow = () => {
// 引入 Vue 組件構造器實例化
const ContextCardContent = Vue.extend(ContextCard)
// 掛載組件
const contextCardContent = new ContextCardContent().$mount()
// 實例化窗口對象
this.amapInfoWindow = new this.AMap.InfoWindow({
isCustom: true,
content: contextCardContent.$el,
offset: new this.AMap.Pixel(0, -40)
})
// 打開窗口
this.amapInfoWindow.open(this.amap, marker.getPosition())
// 監(jiān)聽組件事件關閉窗口
contextCardContent.$on('closeWindow', () => this.amapInfoWindow.close())
}
ContextCard.vue 組件:
<template>
<el-card class="context-box-card box-card">
<div slot="header" class="header">
<span>卡片名稱</span>
<el-button type="text" class="close-btn" @click="closeWindow">關閉</el-button>
</div>
<div v-for="o in 4" :key="o" class="text item">
{{ '列表內容 ' + o }}
</div>
</el-card>
</template>
<script>
export default {
name: 'AMapContextCard',
methods: {
closeWindow() {
this.$emit('closeWindow')
}
}
}
</script>
<style lang="scss" scoped>
.context-box-card {
width: 320px;
height: 200px;
.header {
display: flex;
justify-content: space-between;
align-items: center;
}
::v-deep .el-card__header {
padding: 5px 20px;
}
}
</style>
上面就是一個標點點擊打開標記彈窗的詳細信息,利用 Vue.extend 構造器進行實例化組件。這樣很大程度上提高項目健壯性。
import Vue from "vue";
import App from "./App.vue";
import Element from "element-ui";
import "normalize.css/normalize.css";
import "element-ui/lib/theme-chalk/index.css";
Vue.config.productionTip = false;
Vue.use(Element);
new Vue({
render: (h) => h(App)
}).$mount("#app");
總結
到此這篇關于Vue開發(fā)高德地圖應用的文章就介紹到這了,更多相關Vue高德地圖應用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
基于vue2.0的活動倒計時組件countdown(附源碼下載)
這是一款基于vue2.0的活動倒計時組件,可以使用服務端時間作為當前時間,在倒計時開始和結束時可以自定義回調函數(shù)。這篇文章主要介紹了基于vue2.0的活動倒計時組件countdown,需要的朋友可以參考下2018-10-10
Vue2子組件綁定 v-model,實現(xiàn)父子組件通信方式
這篇文章主要介紹了Vue2子組件綁定 v-model,實現(xiàn)父子組件通信方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04
Element-ui table中過濾條件變更表格內容的方法
下面小編就為大家分享一篇Element-ui table中過濾條件變更表格內容的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03

