VueJS новые значения для реквизита выдвигаются вместо сброса - PullRequest
0 голосов
/ 13 июня 2019

У меня проблема с моим проектом VueJS.Я сделал компонент GoogleMaps в DetailView.vue.Компонент карт использует три реквизита, такие как driver, waypoints и stopOver.

Структура проекта: App.vue содержит Login.vue с маршрутом к основному представлению Dashboard.Внутри этого MainView у меня есть несколько элементов меню, таких как 'Tours' с DataTable внутри.

Нажав на строку данных, VueJS представляет DetailView.vue внутри v-dialog (используя Vuetify).

Внутри этого DetailView есть еще один объект данных, переключатель и вверху мой компонент карты.

<LiefermaxMap style="width: 100%; height: 50%;" :waypoints="waypoints" :driver="driverLocation" :stopOver="showCalculatedTour"></LiefermaxMap>

waypoints и driverLocation - это вычисленные свойства, showCalculatedTour - это обычное свойство , в зависимости от состояния переключателя.

Закрытие этого диалогового окна DetailVue и открытие другого тура приводит к добавлению в набор другого набора путевых точек (и тоже driverLocation) вместо заменыстарые.

waypoints() {
  var points = [];
  if (!this.showCalculatedTour) {
    this.loadnoSpecific.items.items.forEach(element => {
      var p = { lat: element.latitude, lng: element.longitude, done: element.done };
      points.push(p);
    });
  } else {
    this.data.contracts.forEach(element => {
      var c = element.customer.position;
      var p = { lat: c.lat, lng: c.lng, done: element.done }
      points.push(p);
    });
  }
  console.log('points: ' + points)
  return points;
},
driverLocation() {
  const drv = this.data.location;
  const marker = { lat: drv.latitude, lng: drv.longitude };
  return marker;
},

Вот скриншот проекта .

Что я делаю не так?

ОБНОВЛЕНИЕ:

Ожидаемое поведение: удалить все другие путевые точки из предыдущих выбранных туров. Фактическое поведение: путевые точки добавляются к старым

Пример Tours.vue (вид за окном на скриншоте):

    <template>
  <div>
    <v-toolbar flat color="white">
      <v-toolbar-title>Touren</v-toolbar-title>
      <v-spacer></v-spacer>
    </v-toolbar>
    <v-data-table style="width: 70vw;"
                  :headers="headers"
                  :items="tours.items.items"
                  :rows-per-page-items="[5,10,20,50,100]"
                  :loading="isLoading"
                  :total-items="totalItems"
                  :must-sort="true"
                  :pagination.sync="pagination"
                  class="elevation-1"
    >
      <template slot="items" slot-scope="props">
        <tr @click="rowClicked(props.item)">
        <td class="text-xs-left">{{ props.item.loadno }}</td>
        <td class="text-xs-left">{{ props.item.tourname }}</td>
        <td class="text-xs-left">{{ props.item.kfz }}</td>
        <td class="text-xs-left">{{ props.item.driverID }}</td>
        <td class="text-xs-left">{{ props.item.device }}</td>
        <td class="text-xs-left">{{ props.item.created_at | formatDate }}</td>
        </tr>
      </template>
    </v-data-table>
    <v-dialog v-model="showDetail" transition="dialog-bottom-transition" max-width="70vw">
      <TourDetail v-model="showDetail" :data="selectedTour" style="height: 90vh;"></TourDetail>
    </v-dialog>
  </div>
</template>

<script>
import { settings } from '../settings';
import { authHeader } from '../_helpers';
import TourDetail from './TourDetail.vue';
export default {
  name: 'tours',
  components: {
    TourDetail
  },
  data() {
    return {
      totalItems: 0,
      selectedTour: {},
      showDetail: false,
      pagination: {
        descending: true,
        page: 1,
        rowsPerPage: 10,
        sortBy: 'loadno'
      },
      headers: [ // .. ]
    };
  },
  watch: {
    pagination(newValue, oldValue) {
      this.getDataFromApi();
    },
    tours(newValue, oldValue) {
      this.totalItems = newValue.items.total;
    }
  },
  mounted() {
    this.getDataFromApi();
  },
  computed: {
    tours() {
      return this.$store.state.tours.all;
    },
    isLoading() {
      return this.$store.state.tours.loading;
    }
  },
  methods: {
    rowClicked(tour) {
      const requestOptions = {
        method: 'GET',
        headers: authHeader()
      };
      const loadno = tour.loadno;
      console.log('LoadNo: ' + loadno);
      this.$store.dispatch('locations/getLoadnoSpecific', { loadno });
      fetch(
        `${settings.apiUrl}/tours/loadno/complete/` + loadno,
        requestOptions
      ).then(response =>
        response.json().then(json => {
          this.selectedTour = json.tour;
          this.showDetail = true;
        })
      );
    },
    getDataFromApi() {
      const perpage = this.pagination.rowsPerPage;
      const page = this.pagination.page;
      const sortby = this.pagination.sortBy;
      const descending = this.pagination.descending;

      this.$store.dispatch('tours/getAll', {
        perpage,
        page,
        sortby,
        descending
      });
    }
  }
};
</script>

TourDetail.vue

<template>
    <v-flex style="height: 100%;">
      <v-toolbar
          color="primary"
          dark
          flat
          style="z-index: 2; position: absolute;"
        >
          <v-toolbar-title class="justify-center">Fahrer: {{ data.driver.firstname + ' ' + data.driver.lastname  }} &nbsp; | &nbsp;  iPad: {{ data.device }} &nbsp; | &nbsp; Fahrzeug: {{ data.kfz }}</v-toolbar-title>
        </v-toolbar>
      <v-card style="height: 100%; position: relative;">
        <LiefermaxMap style="width: 100%; height: 50%;" :waypoints="waypoints" :driver="driverLocation" :stopOver="showCalculatedTour"></LiefermaxMap>
        <v-layout row wrap style="height: 50%;">
        <v-flex xs12>
          <v-card style="height: 100%;">
          <v-switch v-model="showCalculatedTour" :label="switchLabel" style="position: absolute; right: 10%;"></v-switch>
        <v-data-table
          :headers="headers"
          :items="data.contracts"
          :expand="expand"
          :rows-per-page-text="perPageText"
          style="padding: 5%;"
        >
          <template slot="items" slot-scope="props">
            ...
          </template>
          <template slot="expand" slot-scope="props">
            <v-card>
              <div>
                ...
              </div>
            </v-card>
          </template>
        </v-data-table>
          </v-card>
        </v-flex>
        </v-layout>
      </v-card>
    </v-flex>
</template>

<script>
import LiefermaxMap from '../components/LiefermaxMap.vue';
export default {
  components: {
    LiefermaxMap
  },
  computed: {
    loadnoSpecific() {
      return this.$store.state.locations.loadnoSpecific;
    },
    waypoints() {
      var points = [];
      if (!this.showCalculatedTour) {
        this.loadnoSpecific.items.items.forEach(element => {
          var p = { lat: element.latitude, lng: element.longitude, done: element.done };
          points.push(p);
        });
      } else {
        this.data.contracts.forEach(element => {
          var c = element.customer.position;
          var p = { lat: c.lat, lng: c.lng, done: element.done }
          points.push(p);
        });
      }
      console.log('points: ' + points)
      return points;
    },
    driverLocation() {
      const drv = this.data.location;
      const marker = { lat: drv.latitude, lng: drv.longitude };
      return marker;
    },
    switchLabel() {
      return this.showCalculatedTour ? 'errechnete Route' : 'gefahrene Route';
    }
  },
  props: ['data'],
  data() {
    return {
      showCalculatedTour: false,
      googleWaypoints: [],
      drivenWaypoints: [],
      expand: false,
      perPageText: 'pro Seite',
      completeTourLoading: true,
      completeTour: [{}],
      selectedContract: {},
      headers: [... ]
    };
  },
  methods: { ... }
  }
};
</script>
<style scoped>
// ...
</style>

И компонент LiefermaxMap:

<template>
  <div v-show="mapInitialized" class="liefermaxmap" id="liefermaxmap" ref="liefermaxmap"></div>
</template>
<script>
export default {
  name: 'LiefermaxMap',
  props: ['waypoints', 'driver', 'stopOver'],
  data: function() {
    return {
      mapName: 'liefermaxmap',
      markerCoordinates: [{}],
      mapInitialized: false,
      directionsService: null,
      directionsDisplay: null,
      vueGMap: null,
      bounds: null,
      markers: []
    };
  },
  watch: {
    waypoints(newValue, oldValue) {
      console.log('Waypoints changed, count: ' + newValue.length);
      console.log(newValue)
      this.setWaypoints();
    }
  },
  methods: {
    createGoogleMaps: function() {
      return new Promise((resolve, reject) => {
        let gmap = document.createElement('script');
        gmap.src =
          'https://maps.googleapis.com/maps/api/js?key=XXXX';
        gmap.type = 'text/javascript';
        gmap.onload = resolve;
        gmap.onerror = reject;
        document.querySelector('head').appendChild(gmap);
      });
    },
    initGoogleMaps: function() {
      const localOptions = {
        zoom: 4,
        center: this.driver,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        panControl: true,
        mapTypeControl: true,
        mapTypeControlOptions: {
          position: google.maps.ControlPosition.RIGHT_BOTTOM
        },
        panControlOptions: {
          position: google.maps.ControlPosition.RIGHT_CENTER
        },
        zoomControl: true,
        zoomControlOptions: {
          style: google.maps.ZoomControlStyle.LARGE,
          position: google.maps.ControlPosition.RIGHT_CENTER
        },
        scaleControl: false,
        streetViewControl: false,
        streetViewControlOptions: {
          position: google.maps.ControlPosition.RIGHT_CENTER
        }
      };

      this.vueGMap = new google.maps.Map(
        this.$refs['liefermaxmap'],
        localOptions
      );
      // eslint-disable-next-line
      var drivermarker = new google.maps.Marker({
        position: new google.maps.LatLng(this.driver),
        map: this.vueGMap,
        icon: 'http://maps.google.com/mapfiles/ms/micons/truck.png'
      });
      this.directionsService = new google.maps.DirectionsService();
      this.directionsDisplay = new google.maps.DirectionsRenderer();
      this.directionsDisplay.setMap(this.vueGMap);
      this.mapInitialized = true;
    },
    addMarker(latLng, color) {
      let url = 'http://maps.google.com/mapfiles/ms/icons/';
      url += color + '-dot.png';

      let marker = new google.maps.Marker({
        map: this.vueGMap,
        position: latLng,
        icon: {
          url: url
        }
      });
    },
    setWaypoints() {
      this.directionsService = new google.maps.DirectionsService();
      this.directionsDisplay = new google.maps.DirectionsRenderer();
      this.directionsDisplay.setMap(this.vueGMap);
      var googleWaypoints = [];
      this.waypoints.forEach(element => {
        var pos = new google.maps.LatLng(element.lat, element.lng);
        var wp = { location: pos, stopover: false };
        googleWaypoints.push(wp);
        console.log(element)
        if (element.done == true) {
          this.addMarker(pos, 'green')
        } else {
          this.addMarker(pos, 'red')
        }
      });

      var i = 0;
      var j = 0;
      var temparray = [];
      var chunk = 15;

      for (i = 0, j = googleWaypoints.length; i < j; i += chunk) {
        temparray = googleWaypoints.slice(i, i + chunk);
        var request = {
          origin: 'XXX',
          destination: 'XXX',
          travelMode: 'DRIVING',
          optimizeWaypoints: true,
          waypoints: temparray
        };
        this.directionsService.route(request, (result, status) => {
          if (status === 'OK') {
            this.directionsDisplay.setDirections(result);
            console.log(result);
          }
        });
      }
    },
    googleMapsFailedToLoad() {
      this.vueGMap = 'Error while loading map';
    }
  },
  mounted() {
    this.initGoogleMaps();
  }
};
</script>
<style scoped>
.liefermaxmap {
  width: 100%;
  height: 100%;
}
</style>

1 Ответ

0 голосов
/ 13 июня 2019

vue повторно использует компоненты - используйте key для принудительного монтажа


Измените

<LiefermaxMap style="width: 100%; height: 50%;" :waypoints="waypoints" :driver="driverLocation" :stopOver="showCalculatedTour"></LiefermaxMap>

на

<LiefermaxMap style="width: 100%; height: 50%;" :key="waypoints" :waypoints="waypoints" :driver="driverLocation" :stopOver="showCalculatedTour"></LiefermaxMap>

используйте key, чтобы сообщить Vueне использовать компонент повторно - таким образом, смонтированный может быть запущен,

или перенести ваш метод initMap.

...