开发预览 更新于 2026-05-10

GlobalSearch 全局搜索

全屏覆盖式应用级搜索,支持分类切换 + 分组列表 + path / badge / shortcut。

基础用法

CommandPalette 区别:本组件全屏覆盖(paddingTop 8vh),自带类目过滤芯片 + 标题/路径/badge 三列布局。 适合”应用 spotlight”场景;命令面板适合”⌘K 命令搜索”场景。

背景 视口
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfGlobalSearch, CfButton } from '@chufix-design/vue';
const open = ref(false);
const host = ref<HTMLElement | null>(null);
const results = [
  { id: '1', title: '/v1/orders', description: 'GET 列表所有订单', category: 'API', badge: 'GET', path: 'payments / orders' },
  { id: '2', title: '/v1/orders/{id}', description: 'PUT 更新订单', category: 'API', badge: 'PUT', path: 'payments / orders' },
  { id: '3', title: '[email protected]', description: 'Backend · Payments', category: '人员', path: 'org / payments' },
  { id: '4', title: 'preview.protoforge.io', description: '上次部署 12m 前', category: '环境', path: 'envs / preview' },
  { id: '5', title: 'Reset onboarding', description: '清空所有引导提示', category: '设置', path: 'settings / onboarding' },
  { id: '6', title: 'Export collection', description: '导出为 OpenAPI 3.1', category: '操作', shortcut: '⌘E' },
];
</script>
<template>
  <div ref="host" class="demo-floating-host demo-floating-host--search">
    <div class="demo-row">
      <CfButton @click="open = true">⌘⇧K 打开</CfButton>
    </div>
    <CfGlobalSearch
      :open="open"
      :results="results"
      :to="host ?? 'body'"
      @update:open="(v) => open = v"
      @select="(id) => alert(`Selected: ${id}`)"
    />
  </div>
</template>
<script setup>
import { ref } from 'vue';
import { CfGlobalSearch, CfButton } from '@chufix-design/vue';
const open = ref(false);
const host = ref<HTMLElement | null>(null);
const results = [
  { id: '1', title: '/v1/orders', description: 'GET 列表所有订单', category: 'API', badge: 'GET', path: 'payments / orders' },
  { id: '2', title: '/v1/orders/{id}', description: 'PUT 更新订单', category: 'API', badge: 'PUT', path: 'payments / orders' },
  { id: '3', title: '[email protected]', description: 'Backend · Payments', category: '人员', path: 'org / payments' },
  { id: '4', title: 'preview.protoforge.io', description: '上次部署 12m 前', category: '环境', path: 'envs / preview' },
  { id: '5', title: 'Reset onboarding', description: '清空所有引导提示', category: '设置', path: 'settings / onboarding' },
  { id: '6', title: 'Export collection', description: '导出为 OpenAPI 3.1', category: '操作', shortcut: '⌘E' },
];
</script>
<template>
  <div ref="host" class="demo-floating-host demo-floating-host--search">
    <div class="demo-row">
      <CfButton @click="open = true">⌘⇧K 打开</CfButton>
    </div>
    <CfGlobalSearch
      :open="open"
      :results="results"
      :to="host ?? 'body'"
      @update:open="(v) => open = v"
      @select="(id) => alert(`Selected: ${id}`)"
    />
  </div>
</template>
import { useState } from 'react';
import { CfButton, CfGlobalSearch } from '@chufix-design/react';

export default function Demo() {
  const [open, setOpen] = useState(false);
  const [host, setHost] = useState<HTMLElement | null>(null);
  const results = [
    { id: '1', title: '/v1/orders', description: 'GET 列表所有订单', category: 'API', badge: 'GET', path: 'payments / orders' },
    { id: '2', title: '/v1/orders/{id}', description: 'PUT 更新订单', category: 'API', badge: 'PUT', path: 'payments / orders' },
    { id: '3', title: '[email protected]', description: 'Backend · Payments', category: '人员', path: 'org / payments' },
    { id: '4', title: 'preview.protoforge.io', description: '上次部署 12m 前', category: '环境', path: 'envs / preview' },
    { id: '5', title: 'Reset onboarding', description: '清空所有引导提示', category: '设置', path: 'settings / onboarding' },
    { id: '6', title: 'Export collection', description: '导出为 OpenAPI 3.1', category: '操作', shortcut: '⌘E' },
  ];
  return (
    <>
      <div ref="host" className="demo-floating-host demo-floating-host--search">
          <div className="demo-row">
            <CfButton onClick={() => setOpen(true)}>⌘⇧K 打开</CfButton>
          </div>
          <CfGlobalSearch open={open} results={results} to={host ?? 'body'} onOpenChange={setOpen} onSelect={(id) => alert(`Selected: ${id}`)}
          />
        </div>
    </>
  );
}
import { useState } from 'react';
import { CfButton, CfGlobalSearch } from '@chufix-design/react';

export default function Demo() {
  const [open, setOpen] = useState(false);
  const [host, setHost] = useState<HTMLElement | null>(null);
  const results = [
    { id: '1', title: '/v1/orders', description: 'GET 列表所有订单', category: 'API', badge: 'GET', path: 'payments / orders' },
    { id: '2', title: '/v1/orders/{id}', description: 'PUT 更新订单', category: 'API', badge: 'PUT', path: 'payments / orders' },
    { id: '3', title: '[email protected]', description: 'Backend · Payments', category: '人员', path: 'org / payments' },
    { id: '4', title: 'preview.protoforge.io', description: '上次部署 12m 前', category: '环境', path: 'envs / preview' },
    { id: '5', title: 'Reset onboarding', description: '清空所有引导提示', category: '设置', path: 'settings / onboarding' },
    { id: '6', title: 'Export collection', description: '导出为 OpenAPI 3.1', category: '操作', shortcut: '⌘E' },
  ];
  return (
    <>
      <div ref="host" className="demo-floating-host demo-floating-host--search">
          <div className="demo-row">
            <CfButton onClick={() => setOpen(true)}>⌘⇧K 打开</CfButton>
          </div>
          <CfGlobalSearch open={open} results={results} to={host ?? 'body'} onOpenChange={setOpen} onSelect={(id) => alert(`Selected: ${id}`)}
          />
        </div>
    </>
  );
}

类目过滤

18 个跨 5 个类目的结果。点击顶部 chip 过滤;类目数量 ≤ 1 时自动隐藏 chip 行。

背景 视口
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfGlobalSearch, CfButton } from '@chufix-design/vue';
const open = ref(false);
const host = ref<HTMLElement | null>(null);
const results = Array.from({ length: 18 }, (_, i) => ({
  id: String(i),
  title: ['/v1/orders', '/v1/login', 'jane.l', 'preview env', 'reset onboarding', 'export collection'][i % 6],
  description: 'desc ' + i,
  category: ['API', '人员', '环境', '设置', '操作'][i % 5],
  badge: ['GET', 'POST', '', '', 'env'][i % 5],
  path: 'path/' + i,
  shortcut: i % 4 === 0 ? '⌘E' : undefined,
}));
</script>
<template>
  <div ref="host" class="demo-floating-host demo-floating-host--search">
    <div class="demo-row">
      <CfButton @click="open = true">类目过滤搜索</CfButton>
    </div>
    <CfGlobalSearch
      :open="open"
      :results="results"
      :to="host ?? 'body'"
      @update:open="(v) => open = v"
      @select="(id) => alert(`Selected: ${id}`)"
    />
  </div>
</template>
<script setup>
import { ref } from 'vue';
import { CfGlobalSearch, CfButton } from '@chufix-design/vue';
const open = ref(false);
const host = ref<HTMLElement | null>(null);
const results = Array.from({ length: 18 }, (_, i) => ({
  id: String(i),
  title: ['/v1/orders', '/v1/login', 'jane.l', 'preview env', 'reset onboarding', 'export collection'][i % 6],
  description: 'desc ' + i,
  category: ['API', '人员', '环境', '设置', '操作'][i % 5],
  badge: ['GET', 'POST', '', '', 'env'][i % 5],
  path: 'path/' + i,
  shortcut: i % 4 === 0 ? '⌘E' : undefined,
}));
</script>
<template>
  <div ref="host" class="demo-floating-host demo-floating-host--search">
    <div class="demo-row">
      <CfButton @click="open = true">类目过滤搜索</CfButton>
    </div>
    <CfGlobalSearch
      :open="open"
      :results="results"
      :to="host ?? 'body'"
      @update:open="(v) => open = v"
      @select="(id) => alert(`Selected: ${id}`)"
    />
  </div>
</template>
import { useState } from 'react';
import { CfButton, CfGlobalSearch } from '@chufix-design/react';

export default function Demo() {
  const [open, setOpen] = useState(false);
  const [host, setHost] = useState<HTMLElement | null>(null);
  const results = Array.from({ length: 18 }, (_, i) => ({
    id: String(i),
    title: ['/v1/orders', '/v1/login', 'jane.l', 'preview env', 'reset onboarding', 'export collection'][i % 6],
    description: 'desc ' + i,
    category: ['API', '人员', '环境', '设置', '操作'][i % 5],
    badge: ['GET', 'POST', '', '', 'env'][i % 5],
    path: 'path/' + i,
    shortcut: i % 4 === 0 ? '⌘E' : undefined,
  }));
  return (
    <>
      <div ref="host" className="demo-floating-host demo-floating-host--search">
          <div className="demo-row">
            <CfButton onClick={() => setOpen(true)}>类目过滤搜索</CfButton>
          </div>
          <CfGlobalSearch open={open} results={results} to={host ?? 'body'} onOpenChange={setOpen} onSelect={(id) => alert(`Selected: ${id}`)}
          />
        </div>
    </>
  );
}
import { useState } from 'react';
import { CfButton, CfGlobalSearch } from '@chufix-design/react';

export default function Demo() {
  const [open, setOpen] = useState(false);
  const [host, setHost] = useState<HTMLElement | null>(null);
  const results = Array.from({ length: 18 }, (_, i) => ({
    id: String(i),
    title: ['/v1/orders', '/v1/login', 'jane.l', 'preview env', 'reset onboarding', 'export collection'][i % 6],
    description: 'desc ' + i,
    category: ['API', '人员', '环境', '设置', '操作'][i % 5],
    badge: ['GET', 'POST', '', '', 'env'][i % 5],
    path: 'path/' + i,
    shortcut: i % 4 === 0 ? '⌘E' : undefined,
  }));
  return (
    <>
      <div ref="host" className="demo-floating-host demo-floating-host--search">
          <div className="demo-row">
            <CfButton onClick={() => setOpen(true)}>类目过滤搜索</CfButton>
          </div>
          <CfGlobalSearch open={open} results={results} to={host ?? 'body'} onOpenChange={setOpen} onSelect={(id) => alert(`Selected: ${id}`)}
          />
        </div>
    </>
  );
}

API

属性类型默认值说明
open / v-model:openboolean
resultsGlobalSearchResult[]{ id, title, description?, category, badge?, path?, shortcut?, keywords?, disabled? }
placeholder / emptyText
showCategoriesbooleantrue顶部分类芯片
closeOnSelectbooleantrue
tostring | HTMLElement'body'Teleport 目标;传入局部容器时覆盖层限制在容器内

键盘:↑↓ 导航 · 选中 · Esc 关闭。

反馈与讨论

GlobalSearch 全局搜索 的讨论

0
0 / 600
正在加载评论...