【问题标题】:VueJS - 数据更改后选择列表不更新
【发布时间】:2020-10-27 16:07:27
【问题描述】:

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

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

  • filtersSelected(返回所有带有“isSelected”的过滤器为真)
  • filtersNoSelected(返回所有带有“isSelected”的过滤器为假)

    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.js vuejs2


    【解决方案1】:

    我遇到过类似的问题。这也可能对您的情况有所帮助。当您在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,你不应该改变 直接状态(相似不完全相同)

    您可以在Official docs 中了解它,这表明

    对象必须是普通的

    【讨论】:

    • 感谢您的回答,我不确定何时必须使用“lodash.cloneDeep()”。在计算方法中或当我添加或删除过滤器时?
    • AddFilter 方法中,原因是您正在更改数组内对象的属性
    • 您好 Varun,感谢您的帮助。不幸的是,这对我不起作用。我将这一行放在 addFilter 方法中:this.filters = _.cloneDeep(this.filters);。但我明白了。我会继续调查并通知您。
    猜你喜欢
    • 2017-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-09
    • 2019-05-18
    • 1970-01-01
    • 2019-02-27
    相关资源
    最近更新 更多