Vue開發高德地圖應用的最佳實踐
目錄
- 前言
- 非同步載入
- 封裝元件
- 使用元件
- 自定義介面最佳實踐
- 總結
前言
之前做不過不少關於地圖互動的產品系統,目前國內主流的地圖應用 SDK 只有幾家:高德、百度和騰訊。所以個人覺得在 PC 應用上高德地圖開發相對好一些,至少體驗起來沒有很明顯的坑。這篇文章算是總結下開發地圖應用總結吧。
非同步載入
因為使用 sdk 應用,檔案本身體積很大,所以要注意下載入的白屏時間,解決使用者體驗問題,目前絕大部分產品應用都是 SPA 單頁面應用系統,所以我封裝一個非同步載入的方法:
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
這個方法在載入指令碼的時候先去判斷頁面是否存在該指令碼,如果存在就不會載入第二次,然後再利用載入完畢回撥執行相關方法。
封裝元件
如果系統中有多個頁面需要地圖應用業務,那麼需要封裝一個通用型的地圖元件,提高專案可維護性,我這邊就簡單的封裝下地圖應用:
<template> <div :style="{ width: width,height: height }" class="amap-container" > <div ref="amap" class="amap"> <slot /> </div> </div> </template> <style lang="s" scoped> .amap-container { .amap { width: 100%; height: 100%; } } </style>
指定一個地圖應用容器,外面包裹一層指定高寬,高寬作為外部變數傳入,業務邏輯如下:
import loadScripts from '@/loadScripts' export default { name: 'AMapContainer',props: { width: { require: false,type: String,default: '100%' },height: { require: false,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 事件裡,方便父類元件需要。另外注意要在銷燬生命週期裡對地圖應用進行銷燬,否則會佔用大量的系統記憶體。
使用元件
封裝好元件後就可以在對應的頁面進行引入元件使用即可:
<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,// 地圖物件 http://www.cppcns.comamap: null // 當前地圖例項 }),methods: { /** * 地圖載入完畢回撥 * @param amap * @param AMap */ getAMapData(amap,AMap) { // 從元件獲取地圖 amap 物件 this.amap = amap // 從元件獲取地圖 AMap 靜態物件 this.AMap = AMap } } } </script>
然後在上面基礎上展開相關業務。對於地圖應用來說,最核心的資料就是地圖應用中的座標,無論是地圖的標記元素,折線元素(軌跡等),繪製圖元素等,只需要獲取對應的經緯度資料存到即可,至於怎麼獲取這邊不再詳述。
自定義介面最佳實踐
之前製作的地圖應用,在標記的詳細介面(選擇某個標記左鍵開啟介面),這個介面是需要傳入原生 document 物件,但是在 物件裡面不符合這種寫法,所以導致之前很多系統都是花大量的時間去編寫 dom 結構,甚是頭疼,後續為了解決這個問題,vue 是否有相關方法掛載元件獲取真實的 document 物件,查閱相關文件後,確實有這個 api : Vue.extend,利用這個 api 掛載元件物件即可得到例項化元件的物件。
import ContextCard from './components/ContextCard' // 建立標記 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()) // 監聽元件事件關閉視窗 contextCardContent.$on('closeWindow',() => this.amapInfoWindow.close()) }
ContextCard.vue 元件:
<template> <el-card class="context-box-card box-card"> <div slot="header" class="head客棧er"> <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> <stylhttp://www.cppcns.come 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 "elemeoZxOEnnt-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開發高德地圖應用的文章就介紹到這了,更多相關Vue高德地圖應用內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!