Nuxt中如何调用对象内过滤函数并实现多条件筛选?
Nuxt筛选菜单:修复函数调用错误+实现多条件筛选
问题描述
在Nuxt项目头部实现筛选下拉菜单,用户选择条件后触发过滤函数时出现"... is not a function"错误;同时需要实现多条件同时筛选的功能。
相关代码示例
筛选配置对象
const filters = [ { section: 'Call Types', slug: 'call-types', type: 'multiselect', options: [ { label: 'Inbound', slug: 'inbound', value: true, func: (data) => data.items.filter((item) => { return item.className === 'ib' }), }, { label: 'Outbound', slug: 'outbound', value: true, func: (data) => data.items.filter((item) => { return item.className === 'ob' }), }, ], }, { section: 'Data Types', slug: 'data-types', type: 'multiselect', options: [ { label: 'Sentiment', slug: 'sentiment', value: false, func: (data) => data.items.filter((item) => { return item.d1 === 1 }), }, { label: 'Capture Fails', slug: 'capture-fails', value: false, func: (data) => data.items.filter((item) => { return item.d2 > 0.5 }), }, { label: 'Audio Notes', slug: 'audio-notes', value: false, func: (data) => data.items.filter((item) => { return item.d1 === 1 && item.d2 > 0.5 }), }, ], }, { section: 'Others', slug: 'others', type: 'singleselect', options: [ { label: 'Show All Agents', slug: 'show-all-agents', value: true, func: (data) => data.items.filter((item) => { return item }), }, ], }, ] exports.filters = filters
Timeline组件代码
<template> <vis-timeline :groups="filteredData.groups" :items="filteredData.items" /> </template> <script> import { mapActions, mapState } from 'vuex' import VisTimeline from '~/components/UI/VisTimeline.vue' export default { components: { VisTimeline }, computed: { ...mapState({ callTimeline: (state) => state.agents.callTimeline, timelineLoading: (state) => state.agents.loading, filterOption: (state) => state.agents.filterOption, }), filteredData() { var filtered = Object.assign( {}, JSON.parse(JSON.stringify(this.callTimeline)) ) return this.filterItems(filtered) }, }, methods: { filterItems(data) { if (this.filterOption) { this.filterOption.forEach((filter) => { filter.options.some((option) => { if (option.value) { return option.func(data) } }) }) } return data } } } </script>
Header组件代码
<template> <a-layout-header style="background: #fff; padding: 0"> <a-dropdown :trigger="['click']" :visible="visible" @visibleChange="handleVisible" > <template #overlay> <a-menu> <a-menu-item-group v-for="filter in filters" :key="filter.slug" :title="filter.section" > <a-menu-item :key="filter.slug"> <a-checkbox v-for="option in filter.options" :key="option.slug" :name="option.slug" :checked="option.value" @change="filterChanges" > {{ option.label }} </a-checkbox> </a-menu-item> </a-menu-item-group> <a-menu-divider /> <a-menu-item key="buttons" ><div class="flex justify-between"> <a-button @click="visible = false" type="danger" ghost >Cancel</a-button > <a-button @click="applyFilters" type="primary">Filter</a-button> </div></a-menu-item > </a-menu> </template> <div class="mb-1"> <a-button type="primary"> <div class="flex flex-row justify-center space-x-2 items-center"> <a-icon type="filter" /> <span>Filters</span> <a-icon type="down" /> </div> </a-button> </div> </a-dropdown> </a-layout-header> </template> <script> import { mapActions} from 'vuex' import { filters } from '~/utils/Filters' export default { name: 'DBHeader', data() { return { visible: false, filters: filters, } }, methods: { ...mapActions({ setFilterOption: 'agents/setFilterOption', }), handleVisible(flag) { this.visible = flag }, filterChanges(e) { this.filters.forEach((filter) => { filter.options.some((option) => { if (option.slug === e.target.name) { option.value = e.target.checked } }) }) }, applyFilters() { var filters = Object.assign([], JSON.parse(JSON.stringify(this.filters))) this.setFilterOption(filters) this.visible = false }, }, } </script>
解决方案
1. 修复"is not a function"错误
问题根源:JSON.stringify无法序列化函数类型数据,你在applyFilters中把整个filters对象序列化后存入Vuex,导致filterOption里的func字段丢失,变成undefined。
修改步骤:
步骤1:修改Header组件的applyFilters方法
只存储筛选状态(slug和value),不保存函数:
applyFilters() { // 收集选中的筛选状态,剔除函数 const selectedFilters = this.filters.map(filter => ({ slug: filter.slug, options: filter.options.map(option => ({ slug: option.slug, value: option.value })) })) this.setFilterOption(selectedFilters) this.visible = false }
步骤2:修改Timeline组件的过滤逻辑
导入原始filters配置,关联对应的过滤函数:
<script> import { mapActions, mapState } from 'vuex' import VisTimeline from '~/components/UI/VisTimeline.vue' // 导入原始筛选配置 import { filters as originalFilters } from '~/utils/Filters' export default { components: { VisTimeline }, computed: { ...mapState({ callTimeline: (state) => state.agents.callTimeline, timelineLoading: (state) => state.agents.loading, filterOption: (state) => state.agents.filterOption, }), filteredData() { var filtered = Object.assign( {}, JSON.parse(JSON.stringify(this.callTimeline)) ) return this.filterItems(filtered) }, }, methods: { filterItems(data) { if (!this.filterOption || !this.filterOption.length) return data let filteredItems = [...data.items] // 遍历选中的筛选组 this.filterOption.forEach(filterState => { // 匹配原始配置中的筛选组 const originalFilter = originalFilters.find(f => f.slug === filterState.slug) if (!originalFilter) return // 收集当前组内选中的过滤函数 const activeFuncs = [] filterState.options.forEach(optionState => { if (optionState.value) { const originalOption = originalFilter.options.find(o => o.slug === optionState.slug) if (originalOption?.func) { activeFuncs.push(originalOption.func) } } }) // 叠加执行过滤函数 activeFuncs.forEach(func => { filteredItems = func({ items: filteredItems }).items }) }) data.items = filteredItems return data } } } </script>
2. 实现多条件组合筛选
如果需要支持不同筛选组的逻辑(比如组内多选是OR还是AND),可以给筛选配置添加logic字段:
步骤1:更新筛选配置对象
const filters = [ { section: 'Call Types', slug: 'call-types', type: 'multiselect', logic: 'or', // 组内多选:满足任意一个即可 options: [/* ... */] }, { section: 'Data Types', slug: 'data-types', type: 'multiselect', logic: 'and', // 组内多选:必须满足所有选中项 options: [/* ... */] }, { section: 'Others', slug: 'others', type: 'singleselect', logic: 'single', options: [/* ... */] }, ]
步骤2:修改Timeline组件的filterItems方法
适配不同逻辑的筛选:
filterItems(data) { if (!this.filterOption || !this.filterOption.length) return data let filteredItems = [...data.items] this.filterOption.forEach(filterState => { const originalFilter = originalFilters.find(f => f.slug === filterState.slug) if (!originalFilter) return // 将过滤函数转换为单item的判断函数,方便逻辑组合 const itemCheckers = [] filterState.options.forEach(optionState => { if (optionState.value) { const originalOption = originalFilter.options.find(o => o.slug === optionState.slug) if (originalOption?.func) { // 判断单个item是否符合当前筛选条件 const checker = item => originalOption.func({ items: [item] }).items.length > 0 itemCheckers.push(checker) } } }) if (itemCheckers.length === 0) return // 根据组内逻辑过滤 switch (originalFilter.logic) { case 'or': filteredItems = filteredItems.filter(item => itemCheckers.some(check => check(item))) break case 'and': filteredItems = filteredItems.filter(item => itemCheckers.every(check => check(item))) break case 'single': // 单选逻辑,直接取第一个生效的过滤结果 const firstChecker = itemCheckers[0] filteredItems = filteredItems.filter(firstChecker) break } }) data.items = filteredItems return data }
内容的提问来源于stack exchange,提问作者Halil ibrahim yüce
相关产品推荐
相关产品推荐

