Vue-multiselect несогласованные реактивные параметры

Итак, я создаю приложение, используя Laravel Spark, и поэтому пользуюсь возможностью изучить Vue.js, пока я на нем.

Мне потребовалось больше времени, чтобы разобраться в этом, чем мне бы хотелось, но я почти заставил Vue-multiselect работать с группой параметров, выбранные параметры которых извлекаются с помощью запроса на получение и затем обновляются.

То, как я дошел до этого, вполне может быть далеко не лучшим, так что потерпите меня, но кажется, что он загружает выбранные параметры только в ~ 60% случаев. Чтобы быть ясным - в консоли никогда не регистрируется никаких предупреждений / ошибок, и если я проверю вкладку сети, запросы на получение инструментов наставника всегда успешно возвращают тот же результат ...

Я объявил глобальный массив готовым:

var vm = new Vue({
    data: {
        tutorinstruments: []
    }
});

Затем мой основной компонент делает запрос и обновляет переменную:

    getTutor() {
        this.$http.get('/get/tutor')
            .then(response => {
                this.tutor = response.data;
                this.updateTutor();
            });
    },

    updateTutor() {
        this.updateTutorProfileForm.profile = this.tutor.profile;
        vm.tutorinstruments = this.tutor.instruments;
    },

Мой пользовательский множественный выбор из Vue-multiselect затем выбирает все доступные инструменты и обновляет доступные инструменты, а также те, которые выбраны:

    getInstruments() {
        this.$http.get('/get/instruments')
            .then(response => {
                this.instruments = response.data;
                this.updateInstruments();
            });
    },

    updateInstruments() {
        this.options = this.instruments;
        this.selected = vm.tutorinstruments;
    },

Доступные варианты всегда присутствуют.

Вот ссылка на YouTube, чтобы узнать, как это выглядит, если вы обновляете страницу снова и снова

Я открыт для любых предложений и приветствую помощь!


person davidsneal    schedule 03.02.2017    source источник
comment
Поскольку вы заполняете параметры асинхронно, заполнение параметров может занять несколько мс или пару секунд, верно?   -  person Saurabh    schedule 04.02.2017


Ответы (2)


Ваш глобальный массив var vm = new Vue({...}) - это отдельный экземпляр Vue, который находится за пределами вашего основного экземпляра Vue, который обрабатывает пользовательский интерфейс.

По этой причине в ваших компонентах используются как this, так и vm. В ваших методах this указывает на экземпляр Vue, который обрабатывает пользовательский интерфейс, а vm указывает на ваш глобальный массив, который вы инициализировали вне экземпляра Vue.

Пожалуйста, проверьте эту страницу руководства еще раз: https://vuejs.org/v2/guide/instance.html

Если вы посмотрите на диаграмму жизненного цикла, которая инициализирует все функции Vue, вы заметите, что во многих местах упоминается экземпляр Vue. Эти функции (реактивность, привязка данных и т. Д.) Предназначены для работы в экземпляре Vue, а не в нескольких экземплярах. Время от времени это может сработать, когда наступит подходящий момент, но не обязательно сработает.

Чтобы решить эту проблему, вы можете переделать свое приложение так, чтобы в нем был один экземпляр Vue для обработки пользовательского интерфейса, а также данных.

В идеале я ожидал бы, что ваш tutorinstruments будет загружен в код, который инициализирует ваше приложение (с использованием ловушки mounted в корневом компоненте), и будет сохранен в состоянии Vuex. Когда у вас есть данные в состоянии Vuex, к ним могут получить доступ все компоненты.

Ссылка Vuex: https://vuex.vuejs.org/en/intro.html

Надеюсь, это поможет! Насколько я понимаю, я не дал вам прямого решения вашего вопроса. Возможно, мы можем дождаться более прямого ответа, если вы не можете реструктурировать свое приложение в один экземпляр Vue.

person Mani    schedule 04.02.2017
comment
Спасибо @Mani за ваш ответ :) Вы заставили меня обдумать это, у меня уже есть пользователь, легко доступный с Spark.state.user, поэтому все, что мне нужно было сделать, это добавить $with = ['tutor']; в модель User, и у меня было все, что мне было нужно в Spark.state.user.tutor. Это также сокращает дополнительный HTTP-запрос, чтобы получить его :) - person davidsneal; 04.02.2017

То, что написал Мани, на 100% правильно, причина, по которой я собираюсь вмешаться, заключается в том, что я только что закончил создание очень крупномасштабного проекта с PHP и Vue, и я чувствую, что могу дать вам несколько советов. вещи, которые я узнал в процессе создания веб-сайта PHP (на стороне сервера), но добавив Vue (на стороне клиента) к смеси для создания шаблонов внешнего интерфейса.

Это может быть немного больше, чем объем вашего вопроса с множественным выбором, но я также дам вам твердое начало в этом.

Сначала вам нужно решить, какой из них будет выполнять маршрутизацию (когда пользователи переходят на страницу, обрабатывающую трафик) в вашем веб-приложении, потому что это определит способ, которым вы хотите использовать Vue. Допустим, для обсуждения вы решили аутентифицироваться (если у вас есть логины) с помощью PHP, но вы собираетесь обрабатывать маршрутизацию с помощью Vue на передней панели. В этом случае вы наверняка захотите иметь один основной экземпляр Vue и более или менее настроить что-то похожее на этот пример из Vue Router, притворяясь, что HTML-файл - это ваш PHP index.php в корневом веб-каталоге, в конечном итоге это должен быть единственный .php-файл, который вам нужен с точки зрения создания шаблонов, и я поручил ему обрабатывать все мета заголовка и нижний колонтитул, авторские права, в теле вам просто нужен один div с приложением ID.

Затем вы просто используете маршрутизатор vue и маршруты для загрузки в компоненты vue (легко работает по одному для каждой страницы или категории страниц) для всех ваших страниц. Бонусные баллы, если вы посмотрите на динамический компонент в своем основном приложении. Vue для ленивой загрузки в компонент страницы на основе маршрута, чтобы ваш пакет оставался небольшим.

* подсказка, вам также понадобится полифилл с babel, чтобы сделать этот шаблон

<Component :is="dynamicComponent"/>

сценарий

components: {
  Account: () => import('./Account/Account.vue'),
  FourOhFour: () => import('../FourOhFour.vue')
},
computed: {
  dynamicComponent() {
    return this.$route.name;
  }
},

Теперь, когда мы здесь, мы можем решить вашу проблему с множественным выбором (это также в основном поможет вам понять простой способ загрузки любого компонента для Vue, который вы найдете в Интернете, на свой сайт). В одном из компонентов вашей страницы, которые вы загружаете, когда кто-то посещает маршрут, скажем, / наставник (также я пошел и передал свою информацию аутентификации из PHP в свои маршруты, локализовав ее, а затем используя реквизиты, мета-поля и средства защиты маршрутизатора, все это в этом документе так что я оставлю это вам, если вы хотите изучить) на tutor.vue мы будем называть компонент вашей страницы там, где вы хотите вызвать множественный выбор. Также на данный момент мы все еще подключены к нашему основному экземпляру Vue, поэтому, если вы хотите сослаться на него или свой маршрутизатор из tutor.vue, вы можете просто использовать Vue API практически для всего, что подменяет Vue или vm для этого. Но самое интересное в вашем основном файле / модулях JS, которые вы добавляете к нему за пределами Vue, вы все равно можете использовать API для ссылки на свой основной экземпляр Vue с помощью Vue после того, как вы загрузили основной экземпляр и делали все, что захотите, точно так же, как вы были внутри компонент более-менее.

Именно так я бы обработал добавление внешних компонентов с этого момента, заключив их в другой компонент, которым вы управляете, и сделав их дочерними по отношению к компоненту вашей страницы. Вот очень простой пример с множественным выбором, который притворяется, что родитель - tutor.vue.

Также у меня работает глобальная шина событий, думаю, вам может понравиться идея https://alligator.io/vuejs/global-event-bus/

tutor.vue

<template>
  <div
    id="user-profile"
    class="account-content container m-top m-bottom"
  >

    <select-input
      :saved-value="musicPreviouslySelected"
      :options="musicTypeOptions"
      :placeholder="'Choose an your music thing...'"
      @selected="musicThingChanged($event)"
    />

  </div>
</template>

<script>
import SelectInput from './SelectInput';
import EventBus from './lib/eventBus';

export default {
    components: {
        SelectInput
    },

    data() {
        return {
            profileLoading: true,
            isFullPage: false,
            isModalActive: false,
            slackId: null,
            isActive: false,
            isAdmin: false,
            rep: {
                id: null,
                status: '',
                started: '',
                email: '',
                first_name: '',
            },
            musicTypeOptions: []
        };
    },

    created() {
        if (org.admin) {
            this.isAdmin = true;
        }
        this.rep.id = parseInt(this.$route.params.id);
        this.fetchData();
    },

    mounted() {
        EventBus.$on('profile-changed', () => {
          // Do something because something happened somewhere else client side.
        });
    },

    methods: {
      fetchData() {
        // use axios or whatever to fetch some data from the server and PHP to 
        // load into the page component so say we are getting the musicTypeOptions 
        // which will be in our selectbox.
      },

      musicThingChanged(event) {
        // We have our new selection "event" from multiselect so do something
      }
    }
};
</script>

это наша дочерняя оболочка Multiselect SelectInput.vue

<template>
  <multiselect
    v-model="value"
    :options="options"
    :placeholder="placeholder"
    label="label"
    track-by="value"
    @input="inputChanged" />
</template>

<script>
import Multiselect from 'vue-multiselect';

export default {
    components: { Multiselect },
    props: {
        options: {
            type: [Array],
            default() {
                return [];
            }
        },

        savedValue: {
            type: [Array],
            default() {
                return [];
            }
        },

        placeholder: {
            type: [String],
            default: 'Select Option...'
        }
    },

    data() {
        return {
            value: null
        };
    },

    mounted() {
        this.value = this.savedValue;
    },

    methods: {
        inputChanged(selected) {
            this.$emit('selected', selected.value);
        }
    }
};
</script>

<style scoped>
@import '../../../../../node_modules/vue-multiselect/dist/vue-multiselect.min.css';
</style>

Теперь вы можете убедиться, что вы управляете жизненным циклом своей страницы и какими данными у вас есть когда, вы можете подождать, пока не получите musicTypeOptions, прежде чем он будет передан компоненту SelectInput, который, в свою очередь, настроит Multiselect или любой другой компонент, а затем обработает передачу данные обратно через this. $ emit ('hihiwhatever'), который подбирается @hihiwhatever на компоненте в шаблоне, который вызывает обратно функцию, и теперь вы можете делать что угодно с новым выбором и передавать другие данные в SelectInput и MultiSelect всегда будут синхронизироваться.

А теперь мой последний совет, основанный на опыте. Не поддавайтесь искушению, потому что вы читаете об этом 650 раз в день, и кажется правильным использовать Vuex в такой настройке. У вас уже есть PHP и база данных, используйте его так же, как Vuex, если бы вы делали это в Node.js, что вы не имеете, у вас есть совершенно потрясающее хранилище на стороне сервера PHP, пытаясь управлять данными в Vuex на переднем конце , в то время как наличие данных, управляемых PHP и сервером базы данных, приведет к катастрофе, как только вы начнете иметь несколько пользователей, вошедших в систему, возиться с данными Vuex, которые поступили со стороны сервера PHP, вы не сможете сохранить единую точку истины. Если у вас нет БД на стороне сервера, да, используйте Vuex, но избавьте себя от головной боли и подождите, чтобы попробовать, пока вы не используете Node.js на 100%.

Если вы хотите управлять некоторыми данными на стороне клиента дольше, чем жизненный цикл просмотра страницы, используйте что-то вроде https://github.com/gruns/ImmortalDB он мне очень пригодился.

Извините, это превратилось в сообщение в блоге, ха-ха, но я надеюсь, что это поможет кому-то сэкономить несколько недель.

person rifi2k    schedule 05.01.2019