You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactJS实现自适应结果高度的搜索栏UI(含Axios取消令牌)

React 自适应高度搜索栏实现方案

嘿,我来帮你搞定这个自适应高度的搜索栏!结合你已经写好的Axios请求逻辑,咱们可以分几步完美实现需求:

1. 先理清楚核心需求

咱们要做的是:

  • 用户输入时触发API搜索,用Axios取消令牌避免重复请求
  • 搜索结果容器的高度根据结果数量动态调整:结果少就收缩,结果多(比如10条)就展开到固定高度并支持滚动

2. 完整实现代码&分步说明

我把你的请求逻辑和UI整合在了一起,直接就能用:

import { useState } from 'react';
import axios from 'axios';

function AdaptiveSearchBar() {
  // 输入框内容状态
  const [inputValue, setInputValue] = useState('');
  // 搜索结果列表状态
  const [searchResults, setSearchResults] = useState([]);
  
  // Axios取消令牌相关变量
  let CancelToken = axios.CancelToken; 
  let cancelRequest; 

  // 搜索请求函数(基于你的代码优化)
  const handleSearch = (value) => { 
    // 先取消之前未完成的请求
    if (cancelRequest !== undefined) { 
      cancelRequest(); 
    }
    
    // 空输入时直接清空结果,避免无效请求
    if (!value.trim()) {
      setSearchResults([]);
      return;
    }

    axios 
      .get( 
        `https://example.com/search`, 
        { 
          cancelToken: new CancelToken(function executor(c) { 
            cancelRequest = c; 
          }), 
          params: { q: value }, 
        } 
      )
      .then((response) => { 
        const results = response.data.hits.hits;
        console.log('搜索结果:', results); 
        setSearchResults(results); 
      }) 
      .catch((error) => { 
        // 取消请求的错误不用抛出,避免控制台干扰
        if (!axios.isCancel(error)) {
          console.error('搜索出错:', error); 
        }
      }); 
  };

  // 计算结果列表的自适应高度
  const calculateListHeight = () => {
    const singleItemHeight = 40; // 假设每条结果固定高度40px,可根据你的UI调整
    const maxDisplayItems = 10; // 最多显示10条,超过则滚动
    // 取结果数量和最大显示数的最小值,计算容器高度
    return `${Math.min(searchResults.length, maxDisplayItems) * singleItemHeight}px`;
  };

  return (
    <div style={{ position: 'relative', width: '350px', margin: '2rem auto' }}>
      {/* 搜索输入框 */}
      <input
        type="text"
        value={inputValue}
        onChange={(e) => {
          setInputValue(e.target.value);
          handleSearch(e.target.value);
        }}
        placeholder="输入关键词搜索..."
        style={{
          width: '100%',
          padding: '10px 15px',
          border: '1px solid #e0e0e0',
          borderRadius: '6px',
          fontSize: '15px',
          boxSizing: 'border-box'
        }}
      />

      {/* 自适应高度的结果列表容器 */}
      {searchResults.length > 0 && (
        <div
          style={{
            position: 'absolute',
            top: 'calc(100% + 8px)',
            left: 0,
            right: 0,
            backgroundColor: '#fff',
            border: '1px solid #e0e0e0',
            borderRadius: '6px',
            boxShadow: '0 4px 12px rgba(0,0,0,0.08)',
            // 核心:动态计算高度
            height: calculateListHeight(),
            overflowY: searchResults.length > 10 ? 'auto' : 'hidden',
            zIndex: 100
          }}
        >
          {searchResults.map((item, index) => (
            <div
              key={item._id} // 用API返回的唯一ID当key,不要用index
              style={{
                padding: '10px 15px',
                borderBottom: index < searchResults.length - 1 ? '1px solid #f5f5f5' : 'none',
                cursor: 'pointer',
                transition: 'background-color 0.2s'
              }}
              onClick={() => {
                // 点击结果的交互:填充到输入框+收起列表
                setInputValue(item._source.title); // 替换成你的API返回的显示字段
                setSearchResults([]);
              }}
              onMouseEnter={(e) => e.target.style.backgroundColor = '#f8f8f8'}
              onMouseLeave={(e) => e.target.style.backgroundColor = '#fff'}
            >
              {item._source.title} {/* 替换成你实际要展示的内容,比如标题/描述 */}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

export default AdaptiveSearchBar;

关键细节解释

  • 自适应高度核心:通过calculateListHeight函数动态计算容器高度,结果少于10条时,容器高度会自动收缩到对应内容高度;10条及以上则固定到最大高度并显示滚动条。如果你的结果项高度不固定,也可以把height设为auto,只设置maxHeight: '400px',这样容器会自动适应内容,超过最大值才滚动。
  • 取消令牌优化:新增了空输入判断,避免发送无效请求;同时在catch里过滤掉取消请求的错误,不会在控制台输出冗余信息。
  • UI交互优化:给结果项加了 hover 效果,点击结果会填充到输入框并收起列表,提升用户体验;用API返回的唯一ID作为列表项的key,符合React最佳实践。

3. 可选优化建议

  • 添加防抖:如果不想用户每输入一个字符就触发请求,可以加个300ms左右的防抖,减少API调用次数:
    import { useState, useEffect } from 'react';
    
    // ... 其他代码不变
    
    useEffect(() => {
      const timer = setTimeout(() => {
        handleSearch(inputValue);
      }, 300); // 300ms防抖延迟
      return () => clearTimeout(timer);
    }, [inputValue]);
    
    // 输入框的onChange只更新inputValue,不用直接调用handleSearch
    onChange={(e) => setInputValue(e.target.value)}
    
  • 自定义高度规则:如果你的需求不是固定10条,而是比如“超过5条就展开到固定高度”,只需要修改maxDisplayItems的值即可。

内容的提问来源于stack exchange,提问作者Prabhat kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 20:37:59