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

业务背景

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

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

解决思路

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

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

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

那开发能做什么呢?

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

登场角色

好了,痛点已经出来了,那我们结合当前项目已有的技术栈(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;

总结

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

相关推荐
silvamux_4 分钟前
4款新模型商务邮件翻译横评:0.98到0.46
android·java·javascript
雪芽蓝域zzs8 分钟前
JS 项目转 TS 项目(Vue3 + 若依这类后台项目)完整改造清单
前端·vue.js
定栓18 分钟前
Webpack迁到Vite第四节:SVG 图标系统
前端·webpack·node.js
Dovis(誓平步青云)26 分钟前
车辆进入隧道后信号断开,座舱旅程怎样补回事件
java·开发语言·前端·数据库·电脑
定栓32 分钟前
Webpack迁到Vite第六节:构建配置详解(vite.config.js)
前端·javascript·webpack
风骏时光牛马43 分钟前
从零到精通AI全栈学习路线
前端
Autumn_ing9 小时前
Design.md生成UI怎么验收?举例运营后台的颜色、状态和数据核对
前端·ui·ai·设计系统·paico·ai生成ui·design.md
远离UE410 小时前
UE5 Substrate Thin Film 源码拆析
开发语言·javascript·ue5
keyipatience10 小时前
JavaScript学习(1)书写位置,变量、数据类型、运算符
开发语言·前端·javascript·css·学习