从另一个组件切换地图图层可见性

时间:2018-05-21 22:44:37

标签: javascript vue.js vuejs2 leaflet

首先,我是设计学生,我使用Vue.js为我的高级项目进行原型设计。所以这不是真正的工作项目。只是一些日记应用程序的原型。

我的问题是,我通过Vue2Leaflet构建了一个包含Tile Layer的地图组件。

在Tile Layer上,我渲染了一个GeoJSON文件,该文件有两个坐标对象。

我还有一个datepicker组件,它通过EventBus发出值。

我的目标是:当datepicker发出特定值时,关闭<l-geo-json>并启用另一个<l-geo-json>

<l-geo-json>有一个显示或隐藏:visible的参数。 :visible从GeoJSON对象获取参数。 datepicker会发出一些布尔值来更改GeoJSON参数。 GeoJSON参数更改但不在地图中呈现。

我认为,这是因为没有重新渲染地图组件。

我的地图组件如:

<template>
  <div v-if="refresh" id="MapView2">
    <i class="material-icons geoLocate" v-on:click="geoLoc">location_searching</i>
    <l-map :zoom="zoom" :options="{ zoomControl: false }" class="map" :center="center">
      <l-tile-layer :url="url" :attribution="attribution"></l-tile-layer>
      <l-geo-json :visible="yesterday.day" :geojson="bus.geojson" :options="bus.options"></l-geo-json>
      <l-geo-json :visible="today.day" :geojson="today.geojson" :options="today.options"></l-geo-json>
    </l-map>
  </div>
</template>

<script>
import Vue from 'vue';
import Leaflet from 'leaflet';
import L from 'leaflet';
import { LMap, LTileLayer, LGeoJson } from 'vue2-leaflet';
import PopupContent from './GeoJson2Popup';
import { data, EventBus2 } from '../assets/geojson/sample-geojson.js';


export default {
  name: 'MapView2',
  components: {
    LMap,
    LTileLayer,
    LGeoJson,
  },
  data(){
    return {
      zoom: 13,
      center: {
        lat: '',
        lng: '',
      },
      url:'https://api.mapbox.com/styles/v1/mapbox/light-v9/tiles/256/{z}/{x}/{y}?access_token=...',
      attribution: '',
      yesterday: {
        geojson: data.yesterday,
        day: data.yesterday.visible,
        options: {
          onEachFeature: onEachFeature,
          color: "#45B8FF",
          fillOpacity: 0.8
        }
      },
      today: {
        geojson: data.today,
        day: data.today.visible,
        options: {
          onEachFeature: onEachFeature,
          color: "#45B8FF",
          fillOpacity: 0.8
        }
      },
    }
  },
  methods: {
    geoLoc() {
      navigator.geolocation.getCurrentPosition(position => {
        this.position = position.coords;
        this.center.lat = position.coords.latitude
        this.center.lng = position.coords.longitude
        this.zoom = 25
        console.log(position.coords)
      })
    }
  },
  beforeCreate() {
    if(navigator.geolocation){
      navigator.geolocation.getCurrentPosition(position => {
        this.isLoading = false
        this.position = position.coords;
        this.center.lat = position.coords.latitude
        this.center.lng = position.coords.longitude
        console.log(position.coords)
      })
    }
  },
  mounted() {
    EventBus2.$on('mapDay', pickerValue => {
      switch (pickerValue) {
        case data.today.id:
        data.yesterday.visible = true;
        data.today.visible = false;
        break;
        case data.yesterday.id:
        data.yesterday.visible = false;
        data.today.visible = true;
        break;
      }
    });
  },
};
</script>

而且我的geojson.js文件就像

    import Vue from 'vue';
    export const EventBus2 = new Vue();
    export const data = {
      today: {
        "type": "FeatureCollection",
        "id": "0520",
        "visible": false,
        "features": [ // geojson features and coordinates ]
      },

      yesterday: {
        "type": "FeatureCollection",
        "id": "0520",
        "visible": false,
        "features": [ // geojson features and coordinates ]
      }
  }

如您所见,datepicker以MMDD格式发出一些值。 Switch语句按id检查GeoJSON数据中的值。如果匹配,请更改visible属性。当datepicker发出时,它实际上已经改变了。

但它不是在地图中渲染(GeoJSON图层不会相应地改变可见性)。

我该怎么做?我应该使用watch或类似的东西吗?如果是,我该如何使用它?

1 个答案:

答案 0 :(得分:2)

您只需直接更改实例data

为清楚起见,我会像您从geojson.js文件中导入data2一样。同时调用两者可能是您感到困惑的原因。

import { data as data2, EventBus2 } from '../assets/geojson/sample-geojson.js';

您的GeoJSON图层可见性未动态更改的原因是您使用data中的信息正确初始化了实例daydata2属性,但这并未动态绑定它们未来data2的修改。

因此,最简单的方法是切换data事件监听器中的实例day"mapDay"属性,而不是data2中的信息。

EventBus2.$on('mapDay', pickerValue => {
  switch (pickerValue) {
    case data2.today.id:
      this.yesterday.day = true;
      this.today.day = false;
    break;
    case data2.dun.id:
      this.yesterday.day = false;
      this.today.day = true;
    break;
  }
});

您还可以切换datadata2,以防data2也同步,例如如果你在另一个组件中使用它。请注意,这样的策略会很脆弱,因为更改其他组件中的data2将不起作用。

另一方面,您只需将pickerValue存储在实例data中,然后将其与geojson.id :visible内的:visible="pickerValue === yesterday.geojson.id"进行比较,即可简化您的可见性切换逻辑绑定表达式:Vue.component('map-view-2', { template: '#map-view-2', components: { 'l-map': Vue2Leaflet.LMap, 'l-tile-layer': Vue2Leaflet.LTileLayer, 'l-geo-json': Vue2Leaflet.LGeoJson, }, data() { return { pickerValue: '0520', url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors', yesterday: { geojson: data2.yesterday, }, today: { geojson: data2.today, }, }; }, mounted() { this.$root.$on('mapDay', pickerValue => { this.pickerValue = pickerValue; }); }, }); // Dummy DatePicker component for the sake of the demo. Vue.component('date-picker', { template: '#datepicker', methods: { handleInputChange(event) { this.$root.$emit('mapDay', event.target.value); }, }, }); const data2 = { today: { "type": "FeatureCollection", "id": "0520", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [2.34, 48.86] // Left }, }], }, yesterday: { "type": "FeatureCollection", "id": "0519", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [2.35, 48.86] // Right }, }], }, }; new Vue({ el: '#app', });

代码示例:

<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet-src.js"></script>
<script src="https://unpkg.com/vue2-leaflet@1.0.2/dist/vue2-leaflet.js"></script>

<template id="map-view-2">
  <div id="MapView2">
    <l-map :zoom="11" style="height: 100px;" :center="[48.86, 2.35]">
      <l-tile-layer :url="url" :attribution="attribution"></l-tile-layer>
      <l-geo-json :visible="pickerValue === yesterday.geojson.id" :geojson="yesterday.geojson"></l-geo-json>
      <l-geo-json :visible="pickerValue === today.geojson.id" :geojson="today.geojson"></l-geo-json>
    </l-map>
  </div>
</template>

<template id="datepicker">
  <fieldset @change="handleInputChange">
    <legend>Choose a date</legend>
    <input type="radio" name="date" value="0520" id="today" checked />
    <label for="today">Today 0520</label>
    <input type="radio" name="date" value="0519" id="yesterday" />
    <label for="yesterday">Yesterday 0519</label>
    <input type="radio" name="date" value="none" id="none" />
    <label for="none">None</label>
  </fieldset>
</template>

<div id="app">
  <map-view-2></map-view-2>
  <date-picker></date-picker>
</div>
pickerValue

更模块化的方法会将prop数据公开为"mapDay",以便您直接在父级(例如App)级别修改它,而不必听取Vue.component('map-view-2', { template: '#map-view-2', components: { 'l-map': Vue2Leaflet.LMap, 'l-tile-layer': Vue2Leaflet.LTileLayer, 'l-geo-json': Vue2Leaflet.LGeoJson, }, props: { // Receive the value directly from parent component / App. pickerValue: { type: String, default: '0520', }, }, data() { return { url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors', yesterday: { geojson: data2.yesterday, }, today: { geojson: data2.today, }, }; }, }); // Dummy DatePicker component for the sake of the demo. Vue.component('date-picker', { template: '#datepicker', props: { value: { type: String, default: '0520', }, }, methods: { handleInputChange(event) { // https://vuejs.org/v2/guide/components-custom-events.html#Customizing-Component-v-model this.$emit('input', event.target.value); }, }, }); const data2 = { today: { "type": "FeatureCollection", "id": "0520", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [2.34, 48.86] // Left }, }], }, yesterday: { "type": "FeatureCollection", "id": "0519", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [2.35, 48.86] // Right }, }], }, }; new Vue({ el: '#app', data() { return { pickerValue: '0519', // This value rules child components default value. }; }, }); event:

<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet-src.js"></script>
<script src="https://unpkg.com/vue2-leaflet@1.0.2/dist/vue2-leaflet.js"></script>

<template id="map-view-2">
  <div id="MapView2">
    <l-map :zoom="11" style="height: 100px;" :center="[48.86, 2.35]">
      <l-tile-layer :url="url" :attribution="attribution"></l-tile-layer>
      <l-geo-json :visible="pickerValue === yesterday.geojson.id" :geojson="yesterday.geojson"></l-geo-json>
      <l-geo-json :visible="pickerValue === today.geojson.id" :geojson="today.geojson"></l-geo-json>
    </l-map>
  </div>
</template>

<template id="datepicker">
  <fieldset @change="handleInputChange">
    <legend>Choose a date</legend>
    <input type="radio" name="date" value="0520" id="today" :checked="value === '0520'" />
    <label for="today">Today 0520</label>
    <input type="radio" name="date" value="0519" id="yesterday" :checked="value === '0519'" />
    <label for="yesterday">Yesterday 0519</label>
    <input type="radio" name="date" value="none" id="none" :checked="value === 'none'" />
    <label for="none">None</label>
  </fieldset>
</template>

<div id="app">
  <map-view-2 :picker-value="pickerValue"></map-view-2>
  <date-picker v-model="pickerValue"></date-picker>
</div>
import datetime

commands = {}

while True:
    cmd = input("Enter command: ").lower()
    if "quit" == cmd:
        break

    now = datetime.datetime.now()
    # Command already used at least once?
    if cmd in commands:
        # Check if time has elapsed
        diff = now - commands[cmd]
        if diff.seconds < 10:
            # Time has not elapsed - print warning and start loop over
            print(f"Wait {int(10-diff.seconds)} more seconds before using that command")
            continue
    # If this line is reached, it's ok to use the command
    print(f"Using command: {cmd}")
    # Reset time for this command
    commands[cmd] = now

所有这一切,如果你的工作只是为了设计原型,甚至没有炫耀你的编程技巧,那么即使是Vue,虽然已经非常简单,但可能对你的任务来说太过分了。