在Vue3中为JSON数据的多选项过滤器编写正确代码时出错

zaqlnxep  于 2023-01-31  发布在  Vue.js
关注(0)|答案(1)|浏览(166)

我正在做一个vue项目。我的目标是有一个onchange排序选项,它可以根据下拉列表中的选定值对json文件对象进行排序。第二个目标是有一个动态搜索栏。
我已经实现了这两个功能,这两个功能必须独立于我的第三个目标,这是有一个过滤器选项的复选框列表。当我选择/取消选择一个或多个复选框,然后单击应用按钮,我的过滤器更改应该适用。
目前,当我选中/取消选中复选框时,更改会被应用...但我不希望这样。我希望只有在单击“应用”后才会应用。我尝试过多次更改代码,但要么影响了我的前两个目标,要么发生了一些奇怪的情况,如:
1.当我取消选择中国,选择美国并点击应用时,没有更新发生。
1.当我取消选择两者并点击应用时,我希望返回所有项目,但这并没有发生
1.最初,当页面加载时,不呈现任何项。
我没有发布我的多个代码变体,因为太多了。我发布的是我当前的变体,其中应用按钮是无用的,因为一旦我选择/取消选择复选框,更改就会发生。
有人能提出一个解决方案,只有当应用按钮被点击时,过滤器才会发生,而不会发生奇怪的情况吗?
过滤器必须是独立的搜索和排序功能。搜索和排序必须不依赖于应用按钮。我挣扎着打破逻辑独立在这里。
我的代码

<template>
  <div>
    <input v-model="searchValue" placeholder="Search by title...">
    <label v-for="(country, index) in countries" :key="index">
        <input type="checkbox" v-model="selectedCountries" :value="country"/>{{country}}
    </label>
    <select v-model="sortMethod">
      <option value="alphabetical">Alphabetical</option>
      <option value="numerical">Numerical</option>
    </select>
    <button @click="applyFilter">Apply</button>
    <div v-for="item in filteredItems" :key="item.title">
      <h3>{{ item.title }}</h3>
      <p>{{ item.cost }}</p>
      <p>{{ item.country }}</p>
    </div>
  </div>
</template>

<script>
import { ref, computed } from 'vue'
import jsonData from "../data/test.json"
export default {
  setup() {
    const items = ref(jsonData)
    const searchValue = ref('')
    const selectedCountries = ref([])
    const sortMethod = ref('alphabetical')
  const countries = ref(['USA', 'China'])
    const filteredItems = computed(() => {
        return sortAndSearch(selectedCountries.value, searchValue.value);
    });

    function sortAndSearch(selectedCountries, searchValue) {
        let filtered = items.value;
        if (selectedCountries.length) {
            filtered = filtered.filter(item => selectedCountries.includes(item.country))
        }
        if (searchValue) {
            filtered = filtered.filter(item => item.title.toLowerCase().includes(searchValue.toLowerCase()))
        }
        if (sortMethod.value === 'alphabetical') {
            filtered = filtered.sort((a, b) => a.title.localeCompare(b.title))
        } else {
            filtered = filtered.sort((a, b) => a.cost - b.cost)
        }
        return filtered
    }

    function applyFilter() {
        filteredItems.value = sortAndSearch(selectedCountries.value, searchValue.value)
    }

    return {
        items,
        searchValue,
        selectedCountries,
        sortMethod,
        filteredItems,
        applyFilter
    }
  }
}
</script>
2uluyalo

2uluyalo1#

请看下面的代码片段:(拆分排序和筛选)

const { ref, computed, onMounted } = Vue
const app = Vue.createApp({
  setup() {
    const items = ref([{title: 'aaa', country: 'USA', cost: 40}, {title: 'bbb', country: 'China', cost: 20}, {title: 'ccc', country: 'USA', cost: 30}])
    const searchValue = ref('')
    const selectedCountries = ref([])
    const sortMethod = ref('alphabetical')
    const countries = ref(['USA', 'China'])
    const sorted = ref([])
    onMounted(() => {
      sorted.value = [...items.value]
    })
    const filteredItems = computed(() => {
      return sortMethod.value === 'alphabetical' 
      ? sorted.value.sort((a, b) => a.title.localeCompare(b.title))
      : sorted.value.sort((a, b) => a.cost - b.cost)
    })
    function sortAndSearch() {
      let filtered = [...items.value];
      if (selectedCountries.value.length) {
        filtered = filtered.filter(item => selectedCountries.value.includes(item.country))
      }
      if (searchValue.value) {
        filtered = filtered.filter(item => item.title.toLowerCase().includes(searchValue.value.toLowerCase()))
      }
      sorted.value = filtered
    }

    return {
      countries,
      searchValue,
      selectedCountries,
      sortMethod,
      filteredItems,
      sortAndSearch
    }
  }
})
app.mount('#demo')
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div id="demo">
  <div>
    <input v-model="searchValue" placeholder="Search by title...">
    <label v-for="(country, index) in countries" :key="index">
        <input type="checkbox" v-model="selectedCountries" :value="country" />{{country}}
    </label>
    <select v-model="sortMethod">
      <option value="alphabetical">Alphabetical</option>
      <option value="numerical">Numerical</option>
    </select>
    <button @click="sortAndSearch">Apply</button>
    <div v-for="item in filteredItems" :key="item.title">
      <h3>{{ item.title }}</h3>
      <p>{{ item.cost }}</p>
      <p>{{ item.country }}</p>
    </div>
  </div>
</div>

相关问题