没有重复值的多个下拉列表
Posted
技术标签:
【中文标题】没有重复值的多个下拉列表【英文标题】: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 交互(更改选项、删除),selectedValueArray
和 selectableOptions
数组将相应更改。
我可以用 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>
【问题讨论】:
【参考方案1】:改进的答案,选择disabled
选项的<select>
元素将不会被提交。请改用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 => item.value).length < options.length
完全选择所有选项时隐藏添加按钮,这种方法可以实现吗?
这不行,<select>
选择了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
。但是这个计算属性似乎只“运行”一次而不是反应性的。也许缺少什么?以上是关于没有重复值的多个下拉列表的主要内容,如果未能解决你的问题,请参考以下文章
Yii2 gridview过滤来自多个值的列表(不是下拉列表过滤器)