首页 > 解决方案 > VueJS - 数据更改后选择列表不更新

问题描述

我开始使用 Vuejs,但我很难做一些我认为简单的事情。总而言之,我有一个过滤器列表,其中包含有关过滤器的所有信息(名称、可供选择的项目、选择的女巫项目以及是否选择了过滤器)。在我的页面中,我有一个表格,列出了所有选择的过滤器和下拉列表,其余的过滤器未选择。

为了干净,我在计算部分有两种方法:

    Vue.component('filter-item', {
        props: ['filter'],
        template:
            '<tr>' +
            '<th scope="row">{{ filter.id }}</th>' +
            '<td>' +
            '{{ filter.name }}' +
            '</td>' +
            '<td>' +
            '<button type="button" class="btn btn-sm btn-info">></button>' +
            '</td>' +
            '<td>' +
            '<button type="button" class="btn btn-sm btn-danger" v-on:click="$emit(\'remove\', filter)">X</button>' +
            '</td>' +
            '</tr>'
    
    })
    
    Vue.component('filter-panel', {
        props: ['allfilters'],
        data: function () {
            return {
                filters: this.allfilters
            }
        },
        methods: {
            removeFilter: function (filter) {
                filter.isSelected = false;
            }
        },
        template:
            '<table class="table table-sm">' +
            '<thead>' +
            '<tr>' +
            '<th scope="col">#</th>' +
            '<th scope="col">Name</th>' +
            '<th scope="col">Update</th>' +
            '<th scope="col">Delete</th>' +
            '</tr>' +
            '</thead>' +
            '<tbody>' +
            '<filter-item v-for="filter in filters" v-bind:key="filter.id" v-bind:filter="filter" @remove="removeFilter">' +
            '</filter-item>' +
            '</tbody>' +
            '</table>'
    })
    
    Vue.component('filter-select', {
        props: ['allfilters'],
        data: function () {
            return {
                selectedItem: 0,
                filters: this.allfilters
            }
        },
        methods: {
        },
        template:
            '<div><select class="selectpicker" data-live-search="true" v-model="selectedItem" v-on:change="$emit(\'selected\', selectedItem)"> ' +
            '<option disabled value="0" selected>Select</option>' +
            '<option v-for="filter in filters" v-bind:key="filter.id" v-bind:value="filter.id">{{ filter.name }}' +
            '</option>' +
            '</select>' +
            '<span>{{selectedItem}}</span></div>'
    })

    var app = new Vue({
        el: '#app',
        data: {
            filters:
                [
                    {
                        id: 1,
                        name: "Country",
                        type: "List",
                        isSelected: false,
                        listItem: [
                            {
                                value: "1",
                                text: "France"
                            },
                            {
                                value: "2",
                                text: "United States"
                            },
                            {
                                value: "3",
                                text: "China"
                            }
                        ],
                        selectedItem: ["1", "3"]
                    },
                    {
                        id: 2,
                        name: "Product category",
                        type: "List",
                        isSelected: false,
                        listItem: [
                            {
                                value: "1",
                                text: "Food"
                            },
                            {
                                value: "2",
                                text: "Drink"
                            },
                            {
                                value: "3",
                                text: "Home"
                            }
                        ],
                        selectedItem: ["1"]
                    }
                ],
            filterSelected: 2
        },
        methods:
        {
            AddFilter: function (filterId) {
                var filter = this.filters.find(function (f) { return f.id === filterId });
                filter.isSelected = true;
                $('#FilterModal').modal('hide');
            }
        },
        computed:
        {
            filtersSelected: function () {
                var list = this.filters.filter(function (f) { return f.isSelected });
                return list;
            },
            filtersNoSelected: function () {
                var list = this.filters.filter(function (f) { return !f.isSelected });
                return list;
            }
        }
    })
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<filter-panel v-bind:allfilters="filtersSelected"></filter-panel>
        
<filter-select v-bind:allfilters="filtersNoSelected" v-on:selected="filterSelected = $event"></filter-select> 
<button type="button" class="btn btn-primary" v-on:click="AddFilter(filterSelected)">Add the filter</button>

所以逻辑很简单,当我们选择一个过滤器并单击添加按钮时,该方法会将“isSelected”设置为true。如果我们单击删除,该方法会将“isSelected”设置为 false。之后,计算方法将与我的组件共享过滤列表。但它不起作用。

我在浏览器中一步一步检查逻辑,我们通过计算方法,计算方法每次发送不同的列表,但我的页面没有变化。

我尝试了另一种解决方案,将所有列表共享到我的组件并添加“v-if”或“v-show”,但它仅适用于表格,不适用于下拉列表。此外,我不喜欢这个解决方案。

对于我在这个论坛上阅读的所有帖子,我还没有找到解决问题的方法。(在 v-for 中使用键或使用反应性)

因为我正处于学习阶段,所以我想知道什么是好的方法。我想使用最佳实践!

提前感谢您的帮助!

标签: vue.jsvuejs2

解决方案


我遇到了类似的问题。这也可能对您的情况有所帮助。当您在其中使用数组或对象时data,如果您更改该数组/对象中的数据,则 Vue 无法识别它。

Vue 可以识别您是否将某些数据推送到数组中并重新渲染组件,但如果某些嵌套数据发生更改,它就无法做到这一点。

我们lodash.cloneDeep()在项目中使用来克服这个问题。

突变应该在新副本上执行,你可以尝试这样的事情:

AddFilter: function (filterId) {
  var index = this.filters.findIndex(function (f) { return f.id === filterId });
  let newFilters = _.cloneDeep(this.filters);
  newFilters[index].isSelected = true;
  this.filters = newFilters;
  $('#FilterModal').modal('hide');
}

这个概念类似于 react 中的 state,你不应该直接改变 state(它的相似性不完全相同)

您可以在Official docs中阅读它,这表明

对象必须是普通的


推荐阅读