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

如何在SvelteKit中实现基于API请求的多输入Typeahead搜索(服务端处理)

实现带服务端代理的Typeahead自动补全功能

一、先实现服务端代理接口

由于客户端无法访问httpOnly类型的Cookie,必须通过服务端代理转发请求,由服务端携带Cookie调用目标API。以下是Node.js/Express框架的示例实现:

const express = require('express');
const axios = require('axios');
const router = express.Router();

// 代理自动补全请求
router.get('/api/typeahead/tasks', async (req, res) => {
  try {
    const query = req.query.q;
    if (!query) return res.json([]);

    // 转发请求到目标API,自动携带当前域名下的httpOnly Cookie
    const response = await axios.get('https://目标API地址/tasks/search', {
      params: { q: query },
      withCredentials: true // 关键:开启Cookie携带
    });

    res.json(response.data);
  } catch (error) {
    console.error('代理请求失败:', error);
    res.status(500).json([]); // 出错返回空数组,避免前端异常
  }
});

module.exports = router;

其他后端框架核心逻辑一致:接收客户端搜索参数,带上当前请求的Cookie(服务端可直接访问httpOnly Cookie)转发给目标API,再将结果返回给客户端。

二、修改客户端Svelte代码

添加状态管理、实时请求逻辑和自动补全列表渲染,具体代码如下:

<script lang="ts">
  import { Button, Input, Label } from 'flowbite-svelte';
  import { onMount } from 'svelte';

  export let data;
  let taskId = '';
  let searchResults: string[] = [];
  let isLoading = false;
  let showResults = false;
  let debounceTimeout: NodeJS.Timeout;

  // 自定义防抖函数,避免频繁请求
  const debounceFetch = (query: string) => {
    clearTimeout(debounceTimeout);
    debounceTimeout = setTimeout(async () => {
      if (!query.trim()) {
        searchResults = [];
        showResults = false;
        return;
      }

      isLoading = true;
      try {
        const response = await fetch(`/api/typeahead/tasks?q=${encodeURIComponent(query)}`);
        if (response.ok) {
          searchResults = await response.json();
          showResults = true;
        } else {
          searchResults = [];
        }
      } catch (error) {
        console.error('获取补全结果失败:', error);
        searchResults = [];
      } finally {
        isLoading = false;
      }
    }, 300);
  };

  // 实时监听输入事件
  const onInput = (e: Event) => {
    const target = e.target as HTMLInputElement;
    taskId = target.value;
    debounceFetch(taskId);
  };

  // 选中补全项
  const selectResult = (result: string) => {
    taskId = result;
    searchResults = [];
    showResults = false;
  };

  // 点击外部关闭结果列表
  const handleClickOutside = (e: MouseEvent) => {
    const target = e.target as HTMLElement;
    if (!target.closest('.typeahead-container')) {
      showResults = false;
    }
  };

  onMount(() => {
    document.addEventListener('click', handleClickOutside);
    return () => document.removeEventListener('click', handleClickOutside);
  });
</script>

<div class="max-w-screen-md mx-auto p-6 space-y-8">
  <div class="bg-white shadow-md rounded-lg p-6">
    <div class="text-center mb-8">
      <h2 class="text-2xl font-bold">Task Form</h2>
    </div>
    <div class="relative typeahead-container">
      <Label class="block mb-1">Task ID</Label>
      <Input
        id="taskId"
        name="taskId"
        bind:value={taskId}
        on:input={onInput}
        required
        placeholder="Task id..."
      />

      <!-- 自动补全结果列表 -->
      {#if showResults && searchResults.length > 0}
        <div class="absolute z-10 w-full mt-1 bg-white border border-gray-200 rounded-lg shadow-md max-h-48 overflow-y-auto">
          {#each searchResults as result}
            <div 
              class="px-4 py-2 hover:bg-gray-100 cursor-pointer"
              on:click={() => selectResult(result)}
            >
              {result}
            </div>
          {/each}
        </div>
      {/if}

      <!-- 加载状态提示 -->
      {#if isLoading}
        <div class="mt-2 text-sm text-gray-500">加载中...</div>
      {/if}

      <br />

      <Label class="block mb-1">유저 닉네임</Label>
      <Input label="nickname" id="nickname" name="nickname" required placeholder="nickname..." />
    </div>
  </div>

  <Button type="submit">Create</Button>
</div>

三、优化建议

  • 缓存机制:在客户端缓存已请求过的关键词结果,避免重复请求相同内容
  • 键盘导航:支持上下箭头切换选中项、回车确认,提升操作便捷性
  • 关键词高亮:在补全列表中高亮匹配的关键词,增强视觉引导
  • 空状态处理:当无匹配结果时,显示“暂无匹配内容”的提示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:57:53