【问题标题】:Filter array with multiple conditions and that some of them can be null具有多个条件的过滤器数组,其中一些可以为空
【发布时间】:2020-05-10 22:19:25
【问题描述】:

我有一个用于渲染 vuetify v-list 的 JS 文件,它可以有 2 个级别(具有子节点的节点,这些是可选的)。

我需要从用户输入的搜索框中添加一个过滤器,我可以过滤第一级,但我对第二级有问题,因为有时他们的属性“children”为空,而其他时候他们有值。菜单是这样的:

const Menu = [
    {
        heading: null,
        icon: "mdi-security",
        text: "Login",
        url: {
            name: "login"
        },
        exactUrl: false,
        children: null,
        meta: {
            publicPath: true
        }
    },
    {
        heading: null,
        icon: "search",
        text: "Lista de Funcionarios",
        url: {
            name: "home"
        },
        exactUrl: true,
        children: null,
        meta: {
            publicPath: true
        }
    },
    {
        heading: {
            text: "Mantenimientos",
            publicPath: false
        },
        icon: null,
        text: "",
        url: null,
        exactUrl: null,
        children: null,
        meta: null
    },
    {
        heading: null,
        icon: "mdi-account-group",
        text: "Departamentos",
        url: {
            name: "departamentos"
        },
        exactUrl: false,
        children: null,
        meta: {
            publicPath: false
        }
    },
    {
        heading: null,
        icon: "mdi-account-circle",
        text: "Funcionarios",
        url: {
            name: "funcionarios"
        },
        exactUrl: false,
        children: null,
        meta: {
            publicPath: false
        }
    },
    {
        heading: null,
        icon: "settings",
        text: "Operación",
        url: null,
        exactUrl: false,
        children: [{
            icon: "add",
            text: "Cargar Pedidos",
            url: {
                name: "departamentos"
            }
        },
        {
            icon: "playlist_add_check",
            text: "Aprobar Pedidos",
            url: {
                name: "areas"
            }

        },
        {
            icon: "content_copy",
            text: "Remitir Pedidos",
            url: {
                name: "maps"
            }
        }
        ],
        meta: null
    },
];

export default Menu;

我的计算函数是这样的:

filteredMenu() {
  return this.menus.filter(menu =>
    menu.text.toLowerCase().includes(this.search.toLowerCase())
  );
}

如何在两个级别上同时过滤?

编辑1:“

预期结果:

【问题讨论】:

  • 你能提供一个简单的演示吗?
  • 是的,我已经添加了预期结果的图像

标签: javascript arrays filter multiple-conditions


【解决方案1】:

创建一个可以递归调用的函数。

methods: {
  filterMenuItems(menuItems) {
    return menuItems.filter(menuItem => {
      let found = menuItem.text.toLowerCase().includes(this.search.toLowerCase());
      if (!found && Array.isArray(menuItem.children)) {
        found = this.filterMenuItems(menuItem.children);
      }
      return found;
    });
  }
}

现在您的计算属性可以返回 this.filterMenuItems(this.menus)

filteredMenu() {
    return this.filterMenuItems(this.menus);
}

这也允许无限的子关卡

【讨论】:

  • 我真的很喜欢你的递归建议,尽管它根本不起作用。我添加了一些 console.log 来检查过滤器。使用过滤器“ar”排除第一级的“登录”,但不排除第二级的“Remitir Pedidos”,尽管在控制台中可以看到匹配打印为“false”。我留下了结果的捕获:i.imgur.com/i2blR9k.png
  • 这是意料之中的。 1 个子项包含“ar”(Cargar Pedidos)。我们不会过滤掉子项。
【解决方案2】:

我认为您正在寻找这样的东西,当然它使用递归。但是,它使用递归的方式很重要,这意味着您要首先探测孩子,然后确定是否有孩子(保留父母),如果当前菜单项具有给定的文本,它匹配。您将需要任何匹配子项的父项,对菜单结构的每个分支一直向内,然后返回根级项。

这将调用对子项的探测,然后将整个过程进一步向内运行,直到没有子项,返回每个带有匹配项的向内集(及其关联的父项),然后备份到下一个更高的工作等级。像这张图这样想,

1 match
2 match
        3az < match
        3ay < match
        3ax < match
    3a < [...match] match
    3b < match
3 [...match] match
    4a < match
4 [...match] match
5 match

另外,你不想过滤,你想减少到一个集合

const search = (items, text) => {
  const hasText = item => item.text.toLowerCase().includes(text.toLowerCase())
  const probe = (found, item) => {
    item.children = (item.children || []).reduce(probe, [])

    if (item.children.length || hasText(item)) {
      found.push(item)
    }

    return found
  }

  return items.reduce(probe, [])
}

... elsewhere ...

return search(this.menus, 'c')

https://jsfiddle.net/81wkh5df/6/

这会返回:

  • 功能列表
  • 函数式
  • 行动
    • Cargar Pedidos

【讨论】:

    【解决方案3】:

    您可以使用Destructuring assignment 获取值并设置预定义值,然后使用Some 您可以检查Array 上的truthy 条件。

    也就是说,你需要做的是:

    
    filteredMenu() {
      return this.menus.filter(menu => {
        // check if the parent has the value
        const parentIncludesText = menu.text.toLowerCase().includes(this.search.toLowerCase())
    
        // define a predefined value in case 'children' is null
        const { children = [] } = menu || {}
    
        // check if some of the childs has the value.
        const childrenIncludesText = children.some(child => child.text.toLowerCase().includes(this.search.toLowerCase()))
    
        // then return the result of the parent and the children.
        return parentIncludesText || childrenIncludesText
      });
    }
    

    【讨论】:

    • 解构在哪里?
    • @JaredFarrish const { children = [] } = menu|| {}
    • 这是一种做法。你以前的方式(const children = menu.children || [])也很好用。如果没有它,我会给你一个赞成票(我认为它会混淆问题),但也不会反对它。
    • 是的@JaredFarrish,你一告诉我,我就注意到了 :) 谢谢你之前注意到 :D
    【解决方案4】:

    你可以使用一个有用的函数 _isExist()

    const _isExist = (menu, value) => menu.text.toLowerCase().includes(value.toLowerCase())
    

    如果存在,您可以使用它在 children 数组中进行搜索

    filteredMenu() {
      return this.menus.filter(
        menu =>
            _isExist(menu, this.search) ||
            (menu.children && menu.children.some(childMenu => _isExist(childMenu, this.search))),
      )
    }
    

    【讨论】:

      【解决方案5】:

      如果我是正确的,你想检查它的孩子是否也不是空的?你可以使用&amp;&amp;

      filteredMenu() {
        return this.menus.filter(menu =>
          menu.children && menu.text.toLowerCase().includes(this.search.toLowerCase())
        );
      }
      

      【讨论】:

      • 不行,过滤条件必须是: 1. 第一级的text属性必须过滤,即使children为null或有值。 2.如果children不为null,这也必须通过text属性过滤
      猜你喜欢
      • 2021-01-26
      • 1970-01-01
      • 2021-12-10
      • 2021-07-05
      • 2019-03-02
      • 2021-07-01
      • 2023-03-18
      • 2019-11-20
      • 1970-01-01
      相关资源
      最近更新 更多