React.js 对对象数组的搜索过滤

Ven*_*son 13 javascript reactjs

我正面临search. 它是前端搜索而不是远程搜索,我使用react.js它是因为它是问题中的一个要求并创建了一个名为App. 我的任务是根据类型值显示并突出显示匹配的部分。

我会很感激的。如果你为此提供了一个很好的解决方案。

让我告诉你整个场景。我将这个问题分为 3 个部分。

第 1 部分: 数据的形状是什么?

数据的形状是这样的:

源代码/数据.js:

export default [
    {
        id: 1,
        name: 'Wordpress',
        list: [
            {
                id: 1,
                name: 'Best Mobile App Builder',
                slug: '/'
            },
            {
                id: 2,
                name: 'Best Wordpress Themes',
                slug: '/'
            },
            {
                id: 3,
                name: 'Best Website Creator',
                slug: '/'
            },
            {
                id: 4,
                name: 'Best Wordpress Builder',
                slug: '/'
            }
        ]
    },
    {
        id: 2,
        name: 'SaaS',
        list: [
            {
                id: 1,
                name: 'Appointment Scheduling Software',
                slug: '/'
            },
            {
                id: 2,
                name: 'Design Services',
                slug: '/'
            },
            {
                id: 3,
                name: 'Online Cloud Storage',
                slug: '/'
            },
            {
                id: 4,
                name: 'Remote PC Access',
                slug: '/'
            }
        ]
    },
];
Run Code Online (Sandbox Code Playgroud)

注意

搜索 2 处房产

基本上这是我的过滤功能。

源代码/过滤器.js:

import _ from 'lodash';
import match from 'autosuggest-highlight/match';
import parse from 'autosuggest-highlight/parse';

/**
 * Returns the new filtered array with highlighted parts.
 * @param data {Array<Object>} - The collection to iterate over.
 * @param inputValue {string} - The input value.
 * @return {Array} - Returns the new filtered array.
 */
export const filterByNames = (data, inputValue) => {
    // Create a dynamic regex expression object with ignore case sensitivity
    const re = new RegExp(_.escapeRegExp(inputValue), 'i');
    const results = data.filter((object) => {
        if (re.test(object.name)) {
            return true;
        } else {
            return object.list.some((item) => {
                if (re.test(item.name)) {
                    // Calculates the characters to highlight in text based on query
                    const matches = match(item.name, inputValue);
                    // Breaks the given text to parts based on matches.
                    // After that create a new property named `parts` and assign an array to it.
                    item['parts'] = parse(item.name, matches);
                    return true;
                } else {
                    return false;
                }
            });
        }
    });
    return results;
};
Run Code Online (Sandbox Code Playgroud)

搜索工作正常,但面临两个主要问题。

  1. name属性的上述匹配发生时,它就会停止并且不会更深入。嵌套列表name属性也会发生同样的事情。

  2. 当过滤在幕后发生时,我们通过添加一个名为的新属性来改变原始数据,该属性parts包含突出显示的部分,它是一个对象数组。但我不想改变原始数据,而是想返回包含parts属性的新过滤数组。

看到这个。

整体搜索

工作演示

编辑搜索前端

第 2 部分: 我使用哪些第三方库进行过滤和突出显示?

  • lodash字符串函数escapeRegExp用于转义RegExp 特殊字符。

  • autosuggest-highlight 匹配函数根据查询计算文本中要突出显示的字符。

    之后,来自同一个库的parse函数帮助我们parts根据匹配将给定的文本分解为。最后,它将返回一个带有匹配字符串和highlight 布尔标志的对象数组。所以我们很容易在 UI 上加粗突出显示parts

第 3 部分:应用程序组件

import React, { useState } from 'react';
import { filterByNames } from './filter';
import data from './data';


/**
 * Return the JSX for the List
 * @param data {Array<Object>} - The collection to iterate over.
 * @return {null|*} - Returns the JSX or null.
 */
const renderList = (data) => {
  if (Array.isArray(data) && data.length > 0) {
    return data.map((object) => {
      return (
          <div key={object.id}>
            <h1>{object.name}</h1>
            <ul className="list">
              {object.list.map((item) => {
                return (
                    <li key={item.id}>
                      {item.parts ? (
                          <a href={item.slug}>
                            {item.parts.map((part, index) => (
                                <span
                                    key={index}
                                    style={{ fontWeight: part.highlight ? 700 : 400 }}
                                >
                          {part.text}
                        </span>
                            ))}
                          </a>
                      ) : (
                          <a href={item.slug}>{item.name}</a>
                      )}
                    </li>
                )
              })}
            </ul>
          </div>
      )
    })
  } else {
    return null
  }
};

// Main App Component
const App = () => {

  const [value, setValue] = useState('');

  const onChangeHandler = (event) => {
    const { target } = event;
    const val = target.value;
    setValue(val);
  };

  const results = !value ? data : filterByNames(data, value);
  
    return (
        <div className="demo">
          <input type="text" value={value} onChange={onChangeHandler}/>
          <div className="demo-result">
            { renderList(results) }
          </div>
        </div>
    );
    
};

export default App;
Run Code Online (Sandbox Code Playgroud)

小智 2

这是修改后的代码。

export const filterByNames = (data, inputValue) => {
  // Create a dynamic regex expression object with ignore case sensitivity
  const re = new RegExp(_.escapeRegExp(inputValue), "i");
  const clonedData = _.cloneDeep(data);
  const results = clonedData.filter((object) => {
    return object.list.filter((item) => {
      if (re.test(item.name)) {
        // Calculates the characters to highlight in text based on query
        const matches = match(item.name, inputValue);
        // Breaks the given text to parts based on matches.
        // After that create a new property named `parts` and assign an array to it.
        item["parts"] = parse(item.name, matches);
        return true;
      } else {
        return false;
      }
    }).length > 0 || re.test(object.name);
  });
  return results;
};
Run Code Online (Sandbox Code Playgroud)

此处分叉链接。 https://codesandbox.io/s/search-frontend-forked-e3z55