Vue開(kāi)發(fā)高德地圖應(yīng)用的最佳實(shí)踐
前言
之前做不過(guò)不少關(guān)于地圖交互的產(chǎn)品系統(tǒng),目前國(guó)內(nèi)主流的地圖應(yīng)用 SDK 只有幾家:高德、百度和騰訊。所以個(gè)人覺(jué)得在 PC 應(yīng)用上高德地圖開(kāi)發(fā)相對(duì)好一些,至少體驗(yàn)起來(lái)沒(méi)有很明顯的坑。這篇文章算是總結(jié)下開(kāi)發(fā)地圖應(yīng)用總結(jié)吧。
異步加載
因?yàn)槭褂?js sdk 應(yīng)用,腳本文件本身體積很大,所以要注意下加載的白屏?xí)r間,解決用戶體驗(yàn)問(wèn)題,目前絕大部分產(chǎn)品應(yīng)用都是 SPA 單頁(yè)面應(yīng)用系統(tǒng),所以我封裝一個(gè)異步加載的方法:
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
這個(gè)方法在加載腳本的時(shí)候先去判斷頁(yè)面是否存在該腳本,如果存在就不會(huì)加載第二次,然后再利用加載完畢回調(diào)執(zhí)行相關(guān)方法。
封裝組件
如果系統(tǒng)中有多個(gè)頁(yè)面需要地圖應(yīng)用業(yè)務(wù),那么需要封裝一個(gè)通用型的地圖組件,提高項(xiàng)目可維護(hù)性,我這邊就簡(jiǎn)單的封裝下地圖應(yīng)用:
<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>
指定一個(gè)地圖應(yīng)用容器,外面包裹一層指定高寬,高寬作為外部變量傳入,業(yè)務(wù)邏輯如下:
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) }) } } }
應(yīng)用加載的時(shí)候初始化地圖容器:異步加載高德地圖 js sdk 然后回調(diào)方法里進(jìn)行實(shí)例化地圖應(yīng)用,并且把地圖實(shí)例化的對(duì)象傳入 $emit 事件里,方便父類組件需要。另外注意要在銷毀生命周期里對(duì)地圖應(yīng)用進(jìn)行銷毀,否則會(huì)占用大量的系統(tǒng)內(nèi)存。
使用組件
封裝好組件后就可以在對(duì)應(yīng)的頁(yè)面進(jìn)行引入組件使用即可:
<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, // 地圖對(duì)象 amap: null // 當(dāng)前地圖實(shí)例 }), methods: { /** * 地圖加載完畢回調(diào) * @param amap * @param AMap */ getAMapData(amap, AMap) { // 從組件獲取地圖 amap 對(duì)象 this.amap = amap // 從組件獲取地圖 AMap 靜態(tài)對(duì)象 this.AMap = AMap } } } </script>
然后在上面基礎(chǔ)上展開(kāi)相關(guān)業(yè)務(wù)。對(duì)于地圖應(yīng)用來(lái)說(shuō),最核心的數(shù)據(jù)就是地圖應(yīng)用中的坐標(biāo),無(wú)論是地圖的標(biāo)記元素,折線元素(軌跡等),繪制圖元素等,只需要獲取對(duì)應(yīng)的經(jīng)緯度數(shù)據(jù)存到數(shù)據(jù)庫(kù)即可,至于怎么獲取這邊不再詳述。
自定義界面最佳實(shí)踐
之前制作的地圖應(yīng)用,在標(biāo)記的詳細(xì)界面(選擇某個(gè)標(biāo)記左鍵打開(kāi)界面),這個(gè)界面是需要傳入原生 document 對(duì)象,但是在 vue 對(duì)象里面不符合這種寫法,所以導(dǎo)致之前很多系統(tǒng)都是花大量的時(shí)間去編寫 dom 結(jié)構(gòu),甚是頭疼,后續(xù)為了解決這個(gè)問(wèn)題,vue 是否有相關(guān)方法掛載組件獲取真實(shí)的 document 對(duì)象,查閱相關(guān)文檔后,確實(shí)有這個(gè) api : Vue.extend,利用這個(gè) api 掛載組件對(duì)象即可得到實(shí)例化組件的對(duì)象。
import ContextCard from './components/ContextCard' // 創(chuàng)建標(biāo)記 const marker = new this.AMap.Marker({ map: this.amap, position: [119.058904, 33.537069] }) // 綁定點(diǎn)擊事件 marker.on('click', this.markerInfoWindow) // 點(diǎn)擊打開(kāi)彈窗 const markerInfoWindow = () => { // 引入 Vue 組件構(gòu)造器實(shí)例化 const ContextCardContent = Vue.extend(ContextCard) // 掛載組件 const contextCardContent = new ContextCardContent().$mount() // 實(shí)例化窗口對(duì)象 this.amapInfoWindow = new this.AMap.InfoWindow({ isCustom: true, content: contextCardContent.$el, offset: new this.AMap.Pixel(0, -40) }) // 打開(kāi)窗口 this.amapInfoWindow.open(this.amap, marker.getPosition()) // 監(jiān)聽(tīng)組件事件關(guā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">關(guān)閉</el-button> </div> <div v-for="o in 4" :key="o" class="text item"> {{ '列表內(nèi)容 ' + 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>
上面就是一個(gè)標(biāo)點(diǎn)點(diǎn)擊打開(kāi)標(biāo)記彈窗的詳細(xì)信息,利用 Vue.extend 構(gòu)造器進(jìn)行實(shí)例化組件。這樣很大程度上提高項(xiàng)目健壯性。
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");
總結(jié)
到此這篇關(guān)于Vue開(kāi)發(fā)高德地圖應(yīng)用的文章就介紹到這了,更多相關(guān)Vue高德地圖應(yīng)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于vue2.0的活動(dòng)倒計(jì)時(shí)組件countdown(附源碼下載)
這是一款基于vue2.0的活動(dòng)倒計(jì)時(shí)組件,可以使用服務(wù)端時(shí)間作為當(dāng)前時(shí)間,在倒計(jì)時(shí)開(kāi)始和結(jié)束時(shí)可以自定義回調(diào)函數(shù)。這篇文章主要介紹了基于vue2.0的活動(dòng)倒計(jì)時(shí)組件countdown,需要的朋友可以參考下2018-10-10Vue2子組件綁定 v-model,實(shí)現(xiàn)父子組件通信方式
這篇文章主要介紹了Vue2子組件綁定 v-model,實(shí)現(xiàn)父子組件通信方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04vue設(shè)計(jì)與實(shí)現(xiàn)合理的觸發(fā)響應(yīng)
這篇文章主要為大家介紹了vue設(shè)計(jì)與實(shí)現(xiàn)合理的觸發(fā)響應(yīng)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08Vue3配置vite.config.js解決跨域問(wèn)題的方法
跨域一般出現(xiàn)在開(kāi)發(fā)階段,由于線上環(huán)境前端代碼被打包成了靜態(tài)資源,因而不會(huì)出現(xiàn)跨域問(wèn)題,這篇文章主要給大家介紹了關(guān)于Vue3配置vite.config.js解決跨域問(wèn)題的相關(guān)資料,需要的朋友可以參考下2024-07-07Element-ui table中過(guò)濾條件變更表格內(nèi)容的方法
下面小編就為大家分享一篇Element-ui table中過(guò)濾條件變更表格內(nèi)容的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-03-03