vue-carousel goToPage для программного перехода на выбранную страницу

Я передаю набор локаций в vue-carousel. Я использую ту же коллекцию в нескольких других местах на странице, передавая выбранное местоположение в корень, где хранятся местоположения и выбранное местоположение, в концентраторе событий.

Сложная часть заключалась в том, чтобы заставить карусель перемещаться на нужную страницу — я показываю три местоположения одновременно в больших окнах просмотра и только одно в меньших, используя параметр perPageCustom. Я создаю ключи в API в laravel и в зависимости от размера окна, я перехожу на нужную страницу, и все работает, но когда он загружается, я получаю сообщение об ошибке, потому что ref не существует, когда наблюдатель впервые срабатывает выключенный. Я знаю, что это проблема, но я не уверен, как иметь наблюдателя при изменении местоположения, который не следит за загрузкой страницы ... возможно, с помощью монтирования?

Мой компонент:

<template>
    <div>
        <h3>Locations ({{locations.length}})</h3>
        <p class="lead">Serving California in the greater Sacramento and Los Angeles areas.</p>
        <carousel v-if="locations.length > 0" ref="locations-carousel" :scrollPerPage="true" :perPage="1" :perPageCustom="[[480, 1], [768, 3]]" v-on:pageChange="pageChange">
          <slide v-for="loc in locations" :key="loc.id">
            <div class="card" style="width: 18rem;" v-bind:class="{ closest: loc.is_closest,  active: loc.id == location.id }">
              <img v-on:click="changeLocation(loc.id)" v-if="loc.is_comingsoon === 0" class="card-img-top" :src="'/assets/images/location_'+loc.pathname+'.jpg'" alt="Card image cap">
              <img v-on:click="changeLocation(loc.id)" v-if="loc.is_comingsoon === 1" class="card-img-top" :src="'/assets/images/coming-soon.png'" alt="Card image cap">
              <div class="card-body">
                <h5 class="card-title" v-on:click="changeLocation(loc.id)">{{ loc.name }}</h5>
                <p class="card-text">{{ loc.address }}<br>{{ loc.city_name }}<br>{{ loc.phone | phone }}</p>
                <div class="btn-group" role="group" aria-label="Location Buttons">
                  <a class="btn btn-outline btn-default" :href="'tel:'+ loc.phone"><font-awesome-icon icon="phone"></font-awesome-icon> call</a>
                  <a class="btn btn-outline btn-default" :href="loc.map"><font-awesome-icon icon="globe"></font-awesome-icon> map</a>
                  <a class="btn btn-outline btn-default" v-on:click="changeLocation(loc)" v-bind:class="{ active: loc.id == location.id }"><font-awesome-icon icon="star"></font-awesome-icon> pick</a>
                </div>
                <p class="card-text">{{ loc.note }}</p>
                <span class="badge badge-closest" v-if="loc.is_closest"><font-awesome-icon icon="map-marker"></font-awesome-icon> closest detected</span>
                <span class="badge badge-active" v-if="loc.id == location.id"><font-awesome-icon icon="star"></font-awesome-icon> selected <font-awesome-icon icon="angle-double-down" :style="{ color: 'white' }"></font-awesome-icon></span>
              </div>
            </div>
          </slide>
        </carousel>
        <font-awesome-icon icon="spinner" size="lg" v-if="locations.length < 1"></font-awesome-icon>
    </div>
</template>
<script>
    Vue.filter('phone', function (phone) {
        return phone.replace(/[^0-9]/g, '')
                    .replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
    });
    import { Carousel, Slide } from 'vue-carousel';
    var axios = require("axios");
    export default {
        name: 'locations-carousel',
        props: ['location', 'pg', 'locations'],
        components: {
            Carousel,
            Slide
        },
        data() {
            return {
                debounce: null,
                subs: {},
                clear: 0
            };
        },
        watch: { 
            location: function(newVal, oldVal) { // watch it
                console.log('Prop changed: ', newVal, ' | was: ', oldVal)
                console.log('key: '+this.location.key);
                if( window.innerWidth > 481 ) {
                    if( this.location.pg == 1 ) {
                        this.$refs['locations-carousel'].goToPage(-0);
                    } else {
                        this.$refs['locations-carousel'].goToPage(1);
                    }   
                } else {
                    this.$refs['locations-carousel'].goToPage(this.location.key);
                }
            }
        },
        methods: {
            pageChange(i){ 
                console.log('current Index', i); 
            },
            changeLocation(location) {
                this.$eventHub.$emit('location-loaded', location);              
            }
        }
    }

</script>

Ошибка, которую я получаю:

[Vue warn]: Error in callback for watcher "location": "TypeError: 
Cannot read property 'goToPage' of undefined"

found in

---> <LocationsCarousel> at resources/assets/js/components/LocationsCarousel.vue
   <Root>

TypeError: Cannot read property 'goToPage' of undefined
at VueComponent.location (app.js?v=0.1:53288)
at Watcher.run (app.js?v=0.1:3937)
at flushSchedulerQueue (app.js?v=0.1:3685)
at Array.<anonymous> (app.js?v=0.1:2541)
at flushCallbacks (app.js?v=0.1:2462)

person Dylan Glockler    schedule 11.11.2018    source источник


Ответы (1)


Возможно, вы можете сначала проверить, существует ли this.$refs['locations-carousel'], прежде чем обращаться к его свойствам/методам.

watch: {
  location: function(newVal, oldVal) { // watch it
    console.log('Prop changed: ', newVal, ' | was: ', oldVal)
    console.log('key: ' + this.location.key);
    const locationsCarousel = this.$refs['locations-carousel']
    if (window.innerWidth > 481) {
      if (this.location.pg == 1) {
        locationsCarousel && locationsCarousel.goToPage(-0);
      } else {
        locationsCarousel && locationsCarousel.goToPage(1);
      }
    } else {
      locationsCarousel && locationsCarousel.goToPage(this.location.key);
    }
  }
},
person Husam Ibrahim    schedule 11.11.2018