使用 Vue.js 过滤对象

Filter object with Vue.js

我有一个 Vue.js 组件页面,它从我的后端获取一些数据:

<script setup>
const props = defineProps({
    records: {
        type: Object,
    },
});
</script>

我有三个不同的 filters/states,我希望我的用户能够 select 来自:

下面是我如何获取不同过滤器的记录。我正在使用 collect.js 来更轻松地处理对象:

let getRecords = () => {
    return collect(props.records)
}


const getUnlabeledRecords = () => {
    return getRecords()
        .where('skipped', false)
        .where('processed', false);
}
const getCompletedRecords = () => {
    return getRecords()
        .where('processed', true);
}

const getSkippedRecords = () => {
    return getRecords()
        .where('processed', false)
        .where('skipped', true);
}

//Load all records on page load.
const allRecords = ref(getUnlabeledRecords());

//Show current record to the user.
const current = ref(allRecords.value.first());

然后我的用户可以单击他们想要的过滤器:

<a :class="{'bg-gray-100' : currentFilter === 'Unlabeled' }"
   @click="allRecords = getUnlabeledRecords(), currentFilter = 'Unlabeled'">
    Unlabeled ({{ getUnlabeledRecords().count() }})
</a>
<a :class="{'bg-gray-100' : currentFilter === 'Skipped' }"
   @click="allRecords = getSkippedRecords(), currentFilter = 'Skipped'">
    Skipped ({{ getSkippedRecords().count() }})
</a>
<a :class="{'bg-gray-100' : currentFilter === 'Completed' }"
   @click="allRecords = getCompletedRecords(), currentFilter = 'Completed'">
    Completed ({{ getCompletedRecords().count() }})
</a>

上面的代码可以工作,但是感觉很“笨拙”,而且可扩展性不是很好。比如说,我想引入更高级的过滤 - 或者只是其他“过滤选项”,我必须重复很多代码。

有人对我如何更好地做到这一点有建议吗?

这个问题有点笼统,因为我们不知道您的数据格式,也不知道您将来可能需要什么过滤器。这使得很难给你一个真正好的答案。然而,一个简单的胜利似乎是引入一个过滤器 class/object 来保存您想要过滤的内容的详细信息,例如:

const filters = [
  {
    text: 'Unlabeled',
    statesToFilterOn: [
      { key: 'skipped', value: false },
      { key: 'processed', value: false },
    ]
  },
  {
    text: 'Skipped',
    statesToFilterOn: [
      { key: 'skipped', value: true },
      { key: 'processed', value: false },
    ]
  }
]

现在您可以使用 getFilteredData 方法获取过滤后的数据:

const currentFilteredData = ref(getRecords());
const currentFilter = ref();

function applyFilter(filter) {
  currentFilter.value = filter;
  currentFilteredData.value = getFilteredData(filter);
}

function getFilteredData(filter) {
  let filtered = getRecords();

  filter.statesToFilterOn.forEach(state => {
    filtered = filtered.where(state.key, state.value);
  });

  return filtered;
}

你的 UI 可以是这样的:

<a 
  v-for="filter in filters" 
  :key="filter.text"
  @click="applyFilter(filter)"
>
  {{ filter.text }} ({{ getFilteredData(filter).count }})
</a>

现在,如果您想添加更多过滤器,只需将一个过滤器添加到 filters 数组即可。您可以根据需要多次执行此操作,除了 filters 数组外,您无需更改任何内容。我认为这是我根据所提供的信息所能给出的最佳答案。