产品告诉我养由基也找不到下拉框数据,需要模糊搜索?

业务背景

在日复一日的开发中,产品突然找我,说:"鱼儿,我想下拉框选个数据,我怎么找不到我想选的选项啊?"。我看了一眼产品,当及翻了一个白眼:"哥,你眼神不好吧"。产品看我眼神不对,没有说话,对我甩出一张图,其效果果大概类似这样:

数据有几千条,用户需要从几千条里选出自己想要的选项,我看了看,好家伙,这这这,百步穿杨的养由基怕也得眼神不好啊,于是我默默低下了头,败下阵来:"哥,我优化一下交互"。

解决思路

那怎么解决这个问题呢?先找痛点!!

这个问题的痛点用户如何从海量的数据中找出自己想要的选项

那用户想要的选项是啥呢?开发是不知道的,只有用户自己知道,且每个用户想要的选项是个性化的,开发不能做限制。

那开发能做什么呢?

我想能做的就是提供搜索能力,让用户从原先的肉眼搜索变为机器搜索

登场角色

好了,痛点已经出来了,那我们结合当前项目已有的技术栈(react+ts+vite+antd+loadsh),确定需要登场的角色:

antd的select组件、一双勤劳的手

原有代码

js 复制代码
/**
 * 模糊搜索demo
 */

import React, { useEffect, useState, useCallback } from 'react';
import { Select } from 'antd';

import { getfuzzySearchData } from './service/index'

const FuzzySearch = () => {

    const [options, setOptions] = useState<any[]>([]);

    const fuzzySearchDataApi = async (params?: any) => {
        const res = await getfuzzySearchData(params);
        const { data } = res;
        setOptions(data);
    }


    useEffect(() => {
        fuzzySearchDataApi();
    }, [])

    return (
        <Select
            style={{ width: 120 }}
            options={options}
        />
    )
}

export default FuzzySearch;

具体效果如图:

解决步骤

1、添加搜索能力

利用antd中select的现有能力showSearch 添加上就可以搜索了:

代码如下:

js 复制代码
/**
 * 模糊搜索demo
 */

import React, { useEffect, useState, useCallback } from 'react';
import { Select } from 'antd';

import { getfuzzySearchData } from './service/index'

const FuzzySearch = () => {

    const [options, setOptions] = useState<any[]>([]);

    const fuzzySearchDataApi = async (params?: any) => {
        const res = await getfuzzySearchData(params);
        const { data } = res;
        setOptions(data);
    }


    useEffect(() => {
        fuzzySearchDataApi();
    }, [])

    return (
        <Select
            showSearch // 增加了这个
            style={{ width: 120 }}
            options={options}
        />
    )
}

export default FuzzySearch;

2、模糊搜索

利用已有的filterOption

效果如图:

代码如下:

js 复制代码
 /**
 * 模糊搜索demo
 */

import React, { useEffect, useState, useCallback } from 'react';
import { Select } from 'antd';

import { getfuzzySearchData } from './service/index'

const FuzzySearch = () => {

    const [options, setOptions] = useState<any[]>([]);

    const fuzzySearchDataApi = async (params?: any) => {
        const res = await getfuzzySearchData(params);
        const { data } = res;
        setOptions(data);
    }
    
    // 新增代码,用于筛选需要展示的数据
    const filterOption = (input: string, option: { label: string; value: string }) => {
        return (option?.label ?? '').toLowerCase().includes(input.toLowerCase());
    }

    useEffect(() => {
        fuzzySearchDataApi();
    }, [])

    return (
        <Select
            showSearch
            style={{ width: 120 }}
            options={options}
            filterOption={filterOption} // 新增代码
        />
    )
}

export default FuzzySearch;

上面已经基本解决了模糊搜索的问题,这时候后端老师找我:"鱼儿,产品过来找我,说这个接口太慢了,让我优化一下,我之后不一次性返回所有数据了哈,你给我传个参数,我根据参数一次返回100条吧"。我说好好好,年轻人不讲武德,欺负我一个小前端是吧,我改!!!!!!

3、实时获取数据

上面已经基本解决了模糊搜索的问题,但是又有一个问题,当数据量过于多的时候,后端考虑到接口的速度、性能,可能会做出这样的决策:不会一下子返回几千条数据,只会根据对应的参数返回少量的数据

代码如下:

js 复制代码
/**
 * 模糊搜索demo
 */

import React, { useEffect, useState, useCallback } from 'react';
import { Select } from 'antd';
import { debounce } from 'loadsh'; // 新增代码

import { getfuzzySearchData } from './service/index'

const FuzzySearch = () => {

    const [options, setOptions] = useState<any[]>([]);

    const fuzzySearchDataApi = async (params?: any) => {
        const res = await getfuzzySearchData(params);
        const { data } = res;
        setOptions(data);
    }

    const filterOption = (input: string, option: { label: string; value: string }) => {
        return (option?.label ?? '').toLowerCase().includes(input.toLowerCase());
    }
    
    // 新增代码,用于获取实时数据,使用useCallback防止函数被重复创建,使用debounce用于减少用户请求的次数,进行优化
    const getActualTime = useCallback(debounce(async (value: string) => {
        const params = {
            name: value
        }
        fuzzySearchDataApi(params);
    }, 1000), []);

    useEffect(() => {
        fuzzySearchDataApi();
    }, [])

    return (
        <Select
            showSearch
            style={{ width: 120 }}
            options={options}
            filterOption={filterOption}
            onSearch={(value: string) => { // 使用onSearch,当文本框值变化时调用
                getActualTime(value);
            }}
        />
    )
}

export default FuzzySearch;

效果如图:

4、踩坑

美滋滋的解决模糊搜索的问题后,我看了此页面的另一个有着大数据的select框,决定也浅浅优化一下吧。

优化后代码如下:

js 复制代码
/**
 * 模糊搜索demo
 */

import React, { useEffect, useState, useCallback } from 'react';
import { Select } from 'antd';
import { debounce } from 'loadsh';

import { getfuzzySearchData } from './service/index'

const FuzzySearch = () => {

    const [options, setOptions] = useState<any[]>([]);

    const fuzzySearchDataApi = async (params?: any) => {
        const res = await getfuzzySearchData(params);
        const { data } = res;
        setOptions(data);
    }

    const filterOption = (input: string, option: { label: string; value: string }) => {
        return (option?.label ?? '').toLowerCase().includes(input.toLowerCase());
    }

    const getActualTime = useCallback(debounce(async (value: string) => {
        const params = {
            name: value
        }
        fuzzySearchDataApi(params);
    }, 1000), []);

    useEffect(() => {
        fuzzySearchDataApi();
    }, [])

    return (
        <Select
            showSearch
            style={{ width: 120 }}
            options={options}
            filterOption={filterOption}
            fieldNames={{ label: 'name', value: 'code' }}
            onSearch={(value: string) => {
                getActualTime(value);
            }}
        />
    )
}

export default FuzzySearch;

但是此时,下拉框并没有达到我想要的效果,此时的问题是,当我在搜索框搜索对应的数据的时候,明明下拉框的数据里有该数据,却显示无数据

效果如图:

经过反复对比,我终于发现,问题的关键在于:返回的数据格式,两个数据格式对比:

由此,我们也得到一个antd的机制:fieldNames与filterOption处理的数据都是原始数据的副本,互不影响。虽然我们已经使用fieldNames={{ label: 'name', value: 'code' }}进行了处理,但是filterOption接收的是原始数据,并不是经过fieldNames处理过的数据。

得到这个结论,那我们的处理思路也就很简单了,就是在接收到原始数据进行转化或者直接更改filterOption函数

1、在接收到原始数据进行转化

js 复制代码
/**
 * 模糊搜索demo
 */

import React, { useEffect, useState, useCallback } from 'react';
import { Select } from 'antd';
import { debounce } from 'loadsh';

import { getfuzzySearchData } from './service/index'

const FuzzySearch = () => {

    const [options, setOptions] = useState<any[]>([]);

    // 进行数据处理
    const handleToCodeName = (data: any[]) => {
        const result = [];
        data.forEach((item,index) => {
            result.push({
                label: item.name,
                value: item.code
            })
        }) 
        return result;
    }
    
    const fuzzySearchDataApi = async (params?: any) => {
        const res = await getfuzzySearchData(params);
        const { data } = res;
        setOptions(handleToCodeName(data)); // 在这里进行数据处理函数的调用
    }

    const filterOption = (input: string, option: { label: string; value: string }) => {
        return (option?.label ?? '').toLowerCase().includes(input.toLowerCase());
    }

    const getActualTime = useCallback(debounce(async (value: string) => {
        const params = {
            name: value
        }
        fuzzySearchDataApi(params);
    }, 1000), []);

    useEffect(() => {
        fuzzySearchDataApi();
    }, [])

    return (
        <Select
            showSearch
            style={{ width: 120 }}
            options={options}
            // fieldNames={{ label: 'name', value: 'code' }} // 此时不需要这个
            filterOption={filterOption}
            onSearch={(value: string) => {
                getActualTime(value);
            }}
        />
    )
}

export default FuzzySearch;

2、更改filterOption函数:

js 复制代码
/**
 * 模糊搜索demo
 */

import React, { useEffect, useState, useCallback } from 'react';
import { Select } from 'antd';
import { debounce } from 'loadsh';

import { getfuzzySearchData } from './service/index'

const FuzzySearch = () => {

    const [options, setOptions] = useState<any[]>([]);

    const fuzzySearchDataApi = async (params?: any) => {
        const res = await getfuzzySearchData(params);
        const { data } = res;
        setOptions(data);
    }
    
    // 将label改为name,value改为code
    const filterOption = (input: string, option: { name: string; code: string }) => {
        return (option?.name ?? '').toLowerCase().includes(input.toLowerCase());
    }

    const getActualTime = useCallback(debounce(async (value: string) => {
        const params = {
            name: value
        }
        fuzzySearchDataApi(params);
    }, 1000), []);

    useEffect(() => {
        fuzzySearchDataApi();
    }, [])

    return (
        <Select
            showSearch
            style={{ width: 120 }}
            options={options}
            fieldNames={{ label: 'name', value: 'code' }}
            filterOption={filterOption}
            onSearch={(value: string) => {
                getActualTime(value);
            }}
        />
    )
}

export default FuzzySearch;

总结

以上已经解决了模糊搜索的问题了,产品验收过后,面带意味寻常的微笑离去了

相关推荐
谁呛我名字31 分钟前
大数据应用开发——数据可视化
javascript·vue.js·echarts
前端郭德纲35 分钟前
浅谈React的虚拟DOM
前端·javascript·react.js
2401_879103681 小时前
24.11.10 css
前端·css
ComPDFKit2 小时前
使用 PDF API 合并 PDF 文件
前端·javascript·macos
yqcoder3 小时前
react 中 memo 模块作用
前端·javascript·react.js
谈谈叭3 小时前
Javascript中的深浅拷贝以及实现方法
开发语言·javascript·ecmascript
优雅永不过时·3 小时前
Three.js 原生 实现 react-three-fiber drei 的 磨砂反射的效果
前端·javascript·react.js·webgl·threejs·three
爱编程的鱼4 小时前
javascript用来干嘛的?赋予网站灵魂的语言
开发语言·javascript·ecmascript
神夜大侠6 小时前
VUE 实现公告无缝循环滚动
前端·javascript·vue.js
明辉光焱6 小时前
【Electron】Electron Forge如何支持Element plus?
前端·javascript·vue.js·electron·node.js