目錄結構
這是《基於nuxt和iview搭建OM後臺管理系統實踐》這一個系列文章的目錄,大致思路如下:
- 簡要介紹OM後臺管理系統,以及開發環境
- 自行封裝的公共元件,富文字quill[已完成]、地圖、上傳元件(阿里oss、七牛上傳元件已經完成)的封裝過程
- 專案上線流程,自動化打包(Jenkins)
- 專案總結,總結開發過程中的坑點,避免以後再掉坑
前言
上幾篇記錄了幾個功能比較簡單的元件,本篇的高德地圖封裝遇到了蠻多坑,在此記錄一下,避免後面再踩坑。
說到地圖元件,其實是其他專案組需要地圖資料展示,然後我被借調到其他專案組,最終翻閱高德地圖眾多api後終於完成了。
直接看東西
本地資料原因,沒有完整的展示地圖元件功能,待去公司再擷取動態圖
核心程式碼
// 檔案componets/amap-weather.vue
<template>
<div>
<Form :model="searchForm" :label-width="190" inline>
<FormItem label="地區">
<Select v-model="searchForm.crop" style="width:300px" @on-change="changeImage">
<Option v-for="item in crops" :value="item.title" :key="item.id">{{item.title}}</Option>
</Select>
</FormItem>
</Form>
<div :id="id" :style="{'width':width,'height':height}"></div>
</div>
</template>
<script>
// import VeAmap from 'v-charts/lib/amap';
import axios from "../plugins/axios";
export default {
name: "VAmap",
data() {
return {
weaherData: [],
weatherVoList: [],
arr: [],
polygons: [],
searchForm: {
crop: ''
},
crops: [],
latID: 124.298158,
lngID: 43.223817
};
},
props: {
id: {
default: "container"
},
width: {
default: "100%"
},
zoom: {
default: 15
},
height: {
default: "800px"
},
getlandRequestURL: {
default: ""
},
getgeoJsonURL: {
default: ""
},
getWeatherJsonURL: {
default: ""
},
getAreaData: {
default: ""
}
},
head() {
return {
script: [
{
src: "http://webapi.amap.com/maps?v=1.4.5&key=key自行去高德地圖開發者中心申請&&plugin=AMap.ToolBar"
}
]
};
},
created: function () {
},
mounted() {
var _this = this;
if (process.browser) {
_this.initMap();
_this.getData();
}
},
methods: {
getData() {
var _this = this
axios.get(_this.getAreaData).then(res => {
this.crops = res.data.area
}).catch(error => {
console.log(error);
});
},
changeImage(e) {
var _this = this;
this.polygons = [];
axios.get(_this.getAreaData).then(res => {
var changeData = res.data.area
changeData.forEach(el => {
if (el.title == e) {
this.latID = el.point.lat;
this.lngID = el.point.lng
var _this = this;
this.initMap()
}
})
}).catch(error => {
console.log(error);
});
},
initMap() {
//地圖初始化
var _this = this;
var googleLayer = new AMap.TileLayer({
getTileUrl: "http://mt{1,2,3,0}.google.cn/vt/lyrs=s&hl=zh-CN&gl=cn&x=[x]&y=[y]&z=[z]&s=Galile"
}); //定義谷歌衛星切片圖層
var roadNetLayer = new AMap.TileLayer.RoadNet(); //定義一個路網圖層
var map = new AMap.Map(this.id, {
resizeEnable: true,
center: [_this.latID, _this.lngID],
zoom: _this.zoom,
layers: [googleLayer, roadNetLayer] //設定圖層
});
var toolBar = new AMap.ToolBar({
visible: true
});
map.addControl(toolBar);
// debugger;
// 初始化
var bounds = map.getBounds();
var northeast = bounds.Kb.lng + ',' + bounds.Kb.lat;
var northwest = bounds.Nb.lng + "," + bounds.Kb.lat;
var southwest = bounds.Nb.lng + ',' + bounds.Nb.lat;
var southeast = bounds.Kb.lng + ',' + bounds.Nb.lat;
var area = northeast + ";" + northwest + ";" + southwest + ";" + southeast + ";" + northeast
_this.loadLandData(area, map); //載入可視範圍內的地塊
map.on("moveend", function (e) {
//監聽頁面變化
//獲取可視區域的經緯度
var getBounds = map.getBounds()
var bounds = map.getBounds();
var northeast = bounds.Kb.lng + ',' + bounds.Kb.lat;
var northwest = bounds.Nb.lng + "," + bounds.Kb.lat;
var southwest = bounds.Nb.lng + ',' + bounds.Nb.lat;
var southeast = bounds.Kb.lng + ',' + bounds.Nb.lat;
var area = northeast + ";" + northwest + ";" + southwest + ";" + southeast + ";" + northeast
_this.loadLandData(area, map); //載入可視範圍內的地塊
});
},
loadLandData(area, map) {
//根據當前區域經緯度獲取地圖區域的地塊
let _this = this;
axios
// .get(_this.getlandRequestURL+"?area[]="+area)
.get(_this.getlandRequestURL + "?area[]=" + area)
.then(res => {
let list = res.data.data;
list.forEach(els => {
let obj = [];
let points = els.geometry.coordinates[0].points; //重新組裝介面來的資料
points.forEach(el => {
obj.push(el.coordinates);
});
_this.polygonShow(els.id, map, obj); //遍歷經緯度並渲染到地圖上
});
})
.catch(error => {
console.log(error);
});
},
polygonShow(id, map, obj) {
//渲染多邊形和網格 判斷地塊是否是重新載入的
if (!this.polygons.find(p => p.toString() === id.toString())) {
//渲染多邊形和網格
let polygonOpt = {
path: obj, //設定多邊形邊界路徑
strokeColor: "#FF33FF", //線顏色
strokeOpacity: 0.2, //線透明度
strokeWeight: 3, //線寬
fillColor: "red", //填充色
fillOpacity: 0.4, //填充透明度
id: id,
points: obj
};
let polygon = new AMap.Polygon(polygonOpt);
polygon.setMap(map);
this.polygons.push(id);
this.polygonClick(map, polygon);
}
},
polygonClick(map, polygon) {
//點選地塊獲得格點資料
var _this = this;
polygon.on("click", function (e) {
let list = e.target.Ch.points;
let areas = "";
list.forEach(el => {
areas += el + ";";
});
_this.gridPolygonData(map, _this.removeLastCode(areas)); //載入geoJson
});
},
gridPolygonData(map, areas) {
//載入網格的資料並新增上點選事件
var _this = this;
axios
.get(_this.getWeatherJsonURL + "?point[]=" + areas)
.then(res => {
_this.weaherData = res.data.data;//獲取所有天氣資訊
let list = res.data.data;
let obj = [];
list.forEach(els => {
let points = els.gridPolygon.points; //重新組裝介面來的資料
points.forEach(el => {
obj.push(el.coordinates);
});
_this.gridPolygonShow(els.id, map, obj); //遍歷經緯度並渲染到地圖上
});
})
.catch(error => {
console.log(error);
});
},
// 地圖上載入天氣軌跡
gridPolygonShow(id, map, obj) {
var polygon = new AMap.Polygon({
path: obj, //設定多邊形邊界路徑
strokeColor: "#FF33FF", //線顏色
strokeOpacity: 0.2, //線透明度
strokeWeight: 3, //線寬
fillColor: "#ccc", //填充色
fillOpacity: 0.2, //填充透明度
id: id,
points: obj
});
polygon.setMap(map);//繪製地圖
map.setZoomAndCenter(this.zoom, obj[0]); //重新設定地圖中心點
this.gridPolygonClick(polygon);
},
// 點選地塊觸發的事件
gridPolygonClick(polygon) {
var _this = this;
polygon.on("click", function (e) {
_this.loadWeatherData(e.target.Ch.id); //通過id得到當前的資料
});
},
loadWeatherData(id) {
// 點選格點獲取天氣資料
// alert(id);
var _this = this;
let weatherVoList = [];
let weaherData2 =[];
weaherData2.push(_this.weaherData[0]);
weaherData2.forEach(els => {
if (els.id == id) {
weatherVoList=els.weatherForecastVoList;
}
});
_this.$emit('loadWeather',weatherVoList);//把得到的天氣資料暴露給父元件引用
// _this.dataEmpty = false;
},
removeLastCode(str) {
//去掉字串最後一位
if (str == null || str == "" || str.length < 1) {
return str;
}
return str.substring(0, str.length - 1);
}
}
};
</script>
<style scoped>
.v-charts-data-empty {
position: absolute;
top: 0;
left: 40%;
font-size: 16px;
top: 10%;
}
</style>
複製程式碼
使用方法:按照vue標準引用區域性元件的方式引入即可,分別傳入getlandRequestURL,getgeoJsonURL,getWeatherJsonURL,getAreaData地址。
<template>
<div class="body">
<amap-weather
getlandRequestURL="/data/getLand.json"
getgeoJsonURL="/data/getLand.json"
getWeatherJsonURL="/data/getweatherforgeo.json"
getAreaData="/data/area.json"
></amap-weather>
</div>
</template>
<script>
import amapWeather from '../../components/amap-weather';
export default {
layout:'nav',
components: {
amapWeather
},
head() {
return {
title: "高德地圖外掛"
};
},
}
</script>
<style>
</style>
複製程式碼
總結
- 在封裝高德地圖元件過程中遇到最大的一個坑:nuxt路由跳轉到地圖頁面報錯,最終的解決方案是在left-nav.vue跳轉方法裡做判斷,如果路由路徑為map就重新整理頁面,同時利用:active-name="menuName"屬性展開左側選單;
- 另外一個坑就是服務端渲染帶來的問題,最終在mounted生命週期函式中根據process做判斷是瀏覽器端還是服務端並做相應的處理,如程式碼所示
mounted() {
var _this = this;
if (process.browser) {
_this.initMap();
_this.getData();
}
}
複製程式碼
- 展示的氣象資料需要用到echart圖表展示,這一塊時間限制並沒有做很好的封裝,導致程式碼太亂,後續有時間會做優化;
- 另外對於元件命名也不規範,官方推薦用amap-weather.vue這種,在做這一塊的總結的時候可以看到上面的程式碼改過來了;
系列文章連結
以下為本系列的文章合集,在此列出便於查閱: