基於nuxt和iview搭建OM後臺管理系統實踐(5)-高德地圖地塊氣象資料展示元件的封裝

願愛無憂dk_發表於2018-07-09

封面圖,基於創客貼線上製作

目錄結構

這是《基於nuxt和iview搭建OM後臺管理系統實踐》這一個系列文章的目錄,大致思路如下:

前言

上幾篇記錄了幾個功能比較簡單的元件,本篇的高德地圖封裝遇到了蠻多坑,在此記錄一下,避免後面再踩坑。

說到地圖元件,其實是其他專案組需要地圖資料展示,然後我被借調到其他專案組,最終翻閱高德地圖眾多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這種,在做這一塊的總結的時候可以看到上面的程式碼改過來了;

元件命名規範

系列文章連結

以下為本系列的文章合集,在此列出便於查閱:

相關文章