Vue-multiselect 不一致的反应选项

Vue-multiselect inconsistent reactive options

所以我正在使用 Laravel Spark 构建一个应用程序,因此我借此机会学习了一些 Vue.js。

我花的时间比我希望的要长,但我几乎让 Vue-multiselect 为一组选项工作,通过 get 请求检索所选选项,然后更新.

到目前为止,我所采用的方法可能远非最佳,所以请耐心等待,但它似乎只有约 60% 的时间加载选定的选项。要清楚 - 控制台中从来没有任何 warnings/errors 记录,如果我检查网络选项卡,获取导师仪器的请求总是成功返回相同的结果...

我已经声明了一个全局数组就绪:

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;
    },

可用的选项总是

Here's a YouTube link to how it looks if you refresh the page over and over

我乐于接受任何建议,欢迎提供帮助!

您的全局数组 var vm = new Vue({...}) 是一个单独的 Vue 实例,它位于处理用户界面的主 Vue 实例之外。

这就是您在组件中同时使用 thisvm 的原因。在您的方法中,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 实例,也许我们可以等待更直接的答案。

Mani 写的是 100% 正确的,我要插话的原因是因为我刚刚用 PHP 和 Vue 构建了一个非常大的项目,我觉得我在一个很好的位置,可以给你一些建议/我在构建 PHP(服务器端)网站的过程中学到的东西,但将 Vue(客户端)添加到前端模板的组合中。

这可能比您的多选问题的范围要大一些,但我也会为您提供一个坚实的开端。

首先,您需要确定他们中的哪一个将在您的网络应用程序中执行路由(当用户访问处理流量的页面时),因为这将决定您要使用的方式看。假设为了讨论起见,您决定使用 PHP 进行身份验证(如果您有登录),但您打算在前端使用 Vue 处理路由。在这种情况下,您肯定想要一个主要的 Vue 实例,并且或多或少地设置类似于 Vue Router 中的示例的东西,假装 HTML 文件是您的 PHP index.php 在网络根目录中,这最终应该是唯一的 .php 文件,就模板而言,我需要它处理所有页眉元和页脚版权内容,在正文中你基本上只是想要一个带有 ID 应用程序的 div。

然后你只需使用 vue 路由器和路由来为你的所有页面加载你的 vue 组件(每个页面或页面类别一个很容易工作)。如果您在主要 app.vue 中查找并使用动态组件根据路由在页面组件中进行延迟加载,从而使您的包保持较小,则可获得加分。

*提示你还需要一个带有 babel 的 polyfill 来做到这一点 模板

<Component :is="dynamicComponent"/>

脚本

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

现在我们可以处理您的多选问题(这基本上也将帮助您了解一种简单的方法来将您在网上找到的任何 Vue 组件加载到您的站点中)。在有人访问路由时加载的页面组件之一让我们说/tutor(我还通过本地化然后使用道具,元字段和路由器守卫将我的身份验证信息从 PHP 传递到我的路由中,它所有内容都在该文档中,所以如果您想探索,我会把它留给您)在 tutor.vue 上,我们将称您的页面组件是您要在多选中调用的位置。同样在这一点上,我们仍然连接到我们的主要 Vue 实例,所以如果你想从 tutor.vue 引用它或你的路由器,你可以使用 Vue API 几乎任何替换 Vue 或 vm 的东西.但是巧妙的是在你的主 JS 文件/模块中你在 Vue 之外添加到它你仍然可以使用 API 在你加载主实例之后用 Vue 引用你的主 Vue 实例并做任何你想做的事情就像你或多或少在一个组件中。

这就是我处理添加外部组件的方式,将它们包装在您控制的另一个组件中,并使它们成为页面组件的 child。这是一个非常简单的多选示例,假设 parent 是 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>

这是我们的 child 多选包装器 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 的方法,它对我很有帮助。

抱歉,这变成了一个博客 post 哈哈,但我希望它能帮助人们节省几周的时间。