【问题标题】:Multiple dropdowns with no duplicate value没有重复值的多个下拉列表
【发布时间】:2021-11-11 11:53:13
【问题描述】:

我正在尝试复制一个 Vue 组件,它是一个项目列表,每个项目都包含一个下拉列表和一个删除按钮。将有一个“添加”按钮将新项目添加到列表中,如下面的 sn-p 所示。

要求是,当用户选择一个选项时,该选项对于任何其他项目都将不可用(或删除)。换句话说,选择的选项值不应该重复。这与这个问题中的想法非常相似(jQuery Prevent duplicate choice in multiple dropdowns

当用户重新选择或删除一个项目时,附加到它的选定选项应再次添加到“可用”列表中。因此,选项列表是“反应性的”和动态的。

例如,对于第一项,如果我选择“选项 1”。单击“添加新项目”时,“选项 1”不应在选项列表中。如果第一个项目被删除,“选项 1”将再次可供选择,等等。 . .

这是我目前得到的,想法是option 将存储所有选项数据,selectedValueArray 将负责存储每个项目的选定选项值,selectableOptions 数组将等于 options 设置减去selectedValueArray。通过与 item 交互(更改选项、删除),selectedValueArrayselectableOptions 数组将相应更改。

我可以用 JavaScript 做到这一点。但是我是 Vue 的新手,不知道如何在 Vue 中有效地做到这一点。我创建的 sn-p 的问题是,由于可用的选项来自selectableOptions 数组,所以当从selectableOptions 中删除一个项目时,它也会影响选定的选项。 (例如:如果从该数组中删除“选项 1”,则第一项中的下拉菜单将为空白,因为“选项 1”已从可选列表中删除)。任何帮助表示赞赏。

        var app = new Vue({

            el: "#app",
            data: {
                options: [],
                items: [],
                selectableOptions: [],
                selectedValueArray: [],

            },
            mounted() {
            this.options = [
                    {
                        name: "Option 1",
                        value: 1,
                    },
                    {
                        name: "Option 2",
                        value: 2,
                    },
                    {
                        name: "Option 3",
                        value: 3,
                    },
                    {
                        name: "Option 4",
                        value: 4,
                    },
                    {
                        name: "Option 5",
                        value: 5,
                    },
                    {
                        name: "Option 6",
                        value: 6,
                    }
            ];
                this.selectableOptions = this.options;
            },

            methods: {
                addItem: function () {
                    this.items.push({
                    'value': 0
                    });

                },

                removeItem: function (index) {
                    this.$delete(this.items, index);
                    
                },

                changeOption: function () {
                    this.selectedValueArray = [];
                    for (let i = 0; i < this.items.length; i++) {
                        let selectedValue = this.items[i].value;
                        this.selectedValueArray.push(selectedValue);
                    }
                
                    this.selectableOptions = this.options.filter(                   
                                            option => { 
                        return this.selectedValueArray.indexOf(option.value) == -1;
                      })                 

                },

            },

        })
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
   <div v-for="(item, index) in items">
      <select 
        v-model="item.value">
        <option v-for="(option) in selectableOptions" :value="option.value">{{option.name}}</option>
      </select>
      <button @click="removeItem(index)">Remove this item</button>
   </div>
   <button @click="addItem">Add new item</button>
</div>

【问题讨论】:

    标签: vue.js vuejs2


    【解决方案1】:

    改进的答案,选择disabled 选项的&lt;select&gt; 元素将不会被提交。请改用v-show

    var app = new Vue({
    
      el: "#app",
      data: {
        options: [],
        items: [],
        selectedValueArray: [],
    
      },
      mounted() {
        this.options = [{
            name: "Option 1",
            value: 1,
          },
          {
            name: "Option 2",
            value: 2,
          },
          {
            name: "Option 3",
            value: 3,
          },
          {
            name: "Option 4",
            value: 4,
          },
          {
            name: "Option 5",
            value: 5,
          },
          {
            name: "Option 6",
            value: 6,
          }
        ];
      },
    
      methods: {
        addItem: function() {
          this.items.push({
            'value': 0
          });
    
        },
    
        removeItem: function(index) {
          this.$delete(this.items, index);
    
        },
        
       isShown: function(option) {
            return !(this.items.map(item => item.value).includes(option.value));
          },
    
      },
    
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <div id="app">
      <div v-for="(item, index) in items">
        <select v-model="item.value">
          <option v-for="(option) in options" :value="option.value" v-show="isShown(option)">{{option.name}}</option>
        </select>
        <button @click="removeItem(index)">Remove this item</button>
      </div>
      <button @click="addItem" v-show="items.length<options.length">Add new item</button>
    </div>

    【讨论】:

      【解决方案2】:

      如果您想简单地禁用其值存在于 items 对象数组中的选项(您将其用于 v-model 指令绑定,因此它反映了一组“实时”用户选择的选项) ,那么就是使用方法返回禁用状态了:

      <option v-for="(option) in options" :value="option.value" v-bind:disabled="isDisabled(option)">{{option.name}}</option>
      

      然后,您可以定义一个 isDisabled(option) 方法,该方法返回一个布尔值以指示给定的 option 的值是否已存在于您的数组中:

      isDisabled: function(option) {
          return this.items.map(item => item.value).includes(option.value);
      }
      

      请参阅下面的示例证明:

      var app = new Vue({
      
        el: "#app",
        data: {
          options: [],
          items: [],
          selectedValueArray: [],
      
        },
        mounted() {
          this.options = [{
              name: "Option 1",
              value: 1,
            },
            {
              name: "Option 2",
              value: 2,
            },
            {
              name: "Option 3",
              value: 3,
            },
            {
              name: "Option 4",
              value: 4,
            },
            {
              name: "Option 5",
              value: 5,
            },
            {
              name: "Option 6",
              value: 6,
            }
          ];
        },
      
        methods: {
          addItem: function() {
            this.items.push({
              'value': 0
            });
      
          },
      
          removeItem: function(index) {
            this.$delete(this.items, index);
      
          },
          
          isDisabled: function(option) {
            return this.items.map(item => item.value).includes(option.value);
          }
      
        },
      
      })
      <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
      <div id="app">
        <div v-for="(item, index) in items">
          <select v-model="item.value">
            <option v-for="(option) in options" :value="option.value" v-bind:disabled="isDisabled(option)">{{option.name}}</option>
          </select>
          <button @click="removeItem(index)">Remove this item</button>
        </div>
        <button @click="addItem">Add new item</button>
      </div>

      【讨论】:

      • 这种方法对我来说看起来不错,但不会使逻辑过于复杂
      • 我试图在使用this.items.map(item =&gt; item.value).length &lt; options.length 完全选择所有选项时隐藏添加按钮,这种方法可以实现吗?
      • 这不行,&lt;select&gt; 选择了disabled 选项的元素将不会被提交
      【解决方案3】:

      您必须使用计算属性来过滤 selectableOptions

      类似的东西

      {
      computed: {
          computedSelectable() {
            const chosenValues = this.selectedValueArray.map((i) => i.value);
            return this.selectableOptions.filter((item) =>
              !chosenValues.includes(item.value)
            );
          },
        }
      }
      

      【讨论】:

      • 嗨 Cosimo,按照最常识,我应该将这个计算得到的 computedSelectable 属性添加到 Vue 实例中,并在选项 for 循环中将 selectedValueArray 替换为 computedSelectable。但是这个计算属性似乎只“运行”一次而不是反应性的。也许缺少什么?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-07
      • 1970-01-01
      相关资源
      最近更新 更多