【问题标题】:VueJS: filter select listsVueJS:过滤选择列表
【发布时间】:2020-06-10 08:07:54
【问题描述】:

我有一个 VueJS 应用程序。我有两个列表:A,B

  • A 包含所有元素
  • B 包含来自 A 的一些元素

我有<select> 标签。每个 select 标记必须保存 B 元素的值,并且应该可以选择 B 中不包含的 A 的其他值。

问题:如何正确过滤 A 中不存在于 B 中的元素,但标记当时选择的元素除外?一个通用的解决方案是遍历每个元素并从列表中取消设置不需要的元素。问题是 Vue 具有响应式属性,这意味着当我更改自定义选择的列表时,更改也会传播到其他选择。

我已经包了一个多小时了。我相信我正在为一个简单的问题构建场景,它有一个简单的解决方案,但我找不到它。请帮助我。

const app = new Vue({
  el: '#app',
  data() {
    return {
      b: [],
      a: [
        1, 2, 3, 4, 5
      ],
    }
  },
  methods: {
    filterElements() {
      return this.a.filter((a, a_index) => {
        return !this.b.find((b, b_index) => {
          return a === b
        })
      })
    }
  }

})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <template v-for="i in b.length">
	<select v-model="b[i-1]">
	    <option value="0" disabled>Select a value</option>
	    <!--<option v-for="(item, index) in filterElements()" :value="item">{{ item }}</option> doesn't work -->
	    <option v-for="(item, index) in a" :value="item">{{ item }}</option>
	</select>
	<br>
			
  </template>
  <br>
  <button @click="b.push(0)">+</button>
  <br>
  <br>
  <div>Selected elements: {{ b.join(', ') }}</div>
</div>

【问题讨论】:

    标签: javascript vue.js


    【解决方案1】:

    您可以简单地使用计算属性来包含 A 的过滤版本

    要跟踪 B 中的更改,您必须使用 $set 来更新 B 中的元素。 否则 B 不会反应。更多信息在这里,https://vuejs.org/v2/guide/reactivity.html#For-Arrays

    const app = new Vue({
      el: '#app',
      data() {
        return {
          b: [],
          a: [
            1, 2, 3, 4, 5
          ],
        }
      },
      computed: {
        filteredA() {
          return this.a.filter((a, a_index) => {
            return !this.b.find((b, b_index) => {
              return a === b
            })
          })
        }
      },
      methods: {
        updateB(e, i) {
          // use $set to update array elements to maintain reactivity
          this.$set(this.b, i, +e);
        }
       }
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    
    <div id="app">
      <template v-for="i in b.length">
    	<select :value="b[i-1]" @input="updateB($event.target.value, i-1)">
                <option :value="b[i-1]">{{b[i-1] || "Select a value"}}</option>
    	    <!--<option v-for="(item, index) in filterElements()" :value="item">{{ item }}</option> doesn't work -->
    	    <option v-for="(item, index) in filteredA" :value="item" :key="`${item}-${index}`">{{ item }}</option>
    	</select>
    	<br>
    			
      </template>
      <br>
      <button @click="b.push(0)">+</button>
      <br>
      <br>
      <div>Selected elements: {{ b.join(', ') }}</div>
    </div>

    【讨论】:

    • 我已经更新了我的答案,我想我找到了问题,B的元素变化不会导致filteredA发生变化,这是因为如果直接更改,vue的反应性不会触发数组元素变化.您能否检查更新的解决方案是否有效? @user8555937
    • 试试 sn-p 看看它是否能产生想要的结果
    • 可爱!谢谢
    • 选择框以字符串形式返回选择的值,表示为ee 之前的 + 符号只是将其转换为数字
    【解决方案2】:

    无需手动过滤。这是一个循环您的 a 数组并将所选值绑定到 b 的解决方案:

    https://stackoverflow.com/a/50648659/13602136

    【讨论】:

    • 不回答我的问题
    • 哦,对,对不起。问题:这里的用例是什么?每个生成的select 都会过滤掉已经选择的选项?为什么不只使用一个多选?
    • 一个多选可能会成功。虽然由于某些原因我必须保持这种布局。
    • 每个生成的选择必须包含 A 中不存在于 B 中的所有元素
    • 我认为您需要使用computed setter 进行v-model,并在您的A 数组上使用.splice() 方法来删​​除或添加项目。
    【解决方案3】:

    如果我理解正确,您想做一个数组减法(A 中的元素不在 B 中):

    function aNotInB(a, b) {
      return a.filter(aElement => {
        // .find() returns undefined if nothing is found
        // (b.find(element) === undefined) returns true if a element is not found in b
        return b.find(bElement => aElement === bElement) === undefined
      })
    }
    
    a = [1, 2, 3, 4, 5]
    b = [2, 3, 4]
    
    
    console.log(aNotInB(a,b))    // [1, 5]

    【讨论】:

    • 这和我做的一样。检查sn-p
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 2014-02-12
    • 2010-10-15
    • 2017-11-07
    • 1970-01-01
    相关资源
    最近更新 更多