组件/SearchPanel 内联搜索面板

SearchPanel 内联搜索面板

卡片式内联搜索:输入框、实时结果与空态合为一体。

Verified自 0.3.9

SearchPanel 内联搜索面板

基础用法

SearchPanel

实时过滤与键盘导航

↑ ↓ 移动、Enter 选中、Esc 清空;三个字符起才显示空态。

示例加载中...

与 TxCommandPalette 的分工

两者都是"搜索 + 结果列表",但形态是互斥的:

  • TxCommandPalette模态——Teleport 到 body、全屏遮罩、role="dialog" aria-modal="true"、焦点陷阱、z-index 分配。它接管整个页面。
  • TxSearchPanel内联——没有遮罩、没有模态语义、没有焦点陷阱。它可以放进页面、侧边栏或浮层里,与周围内容共存。

需要全局唤起的命令面板用前者;需要在版面里长驻一块搜索区用后者。两者的键盘契约一致,用户不需要重新学。

空查询、空态与阈值

  • 空查询时只展示前 idleCount(默认 5)条。短清单读起来是"起点",整份倾倒读起来是"一堵墙"。传 0 展示全部。
  • 空态要等查询满 emptyThreshold(默认 3)个字符才出现。1–2 个字符且无匹配时列表保持空白——这是刻意的,避免打字途中"没有结果"来回闪烁。minHeight(默认 248)在此期间撑住版面。
  • 空态本身复用 TxSearchEmpty,只通过它公开的 CSS 变量调整密度与配色,并用 icon 插槽替换掉那张 64px 的动画插画,没有触碰它的内部类名。

API

Props

属性名类型默认值说明
modelValuestring''查询文本(v-model)。
itemsSearchPanelItem[][]候选项。
placeholderstring'Search'输入框占位符。
ariaLabelstring-输入框可访问名,回退到 placeholder。
idleCountnumber5空查询时展示的条数,0 表示全部。
emptyThresholdnumber3允许渲染空态的最短查询长度。
emptyTitlestring'No results found'空态标题。
emptyDescriptionstring'Adjust your search to try again'空态说明。
clearLabelstring'Clear search'清除按钮的可访问名。
listLabelstring'Search results'结果列表的可访问名。
minHeightnumber | string248预留高度,避免结果增减时版面跳动。
filter(items, query) => items-覆盖内建匹配(对 labelkeywords 做大小写无关的 includes)。
clearablebooleantrue是否渲染清除按钮。
disabledbooleanfalse禁用输入。

Types

名称说明
SearchPanelItem{ id, label, keywords?, disabled? }keywords 参与内建匹配但不显示。

Slots

名称说明
item替换单行内容,作用域 { item, active, query }
empty替换空态,作用域 { query }
footer追加在列表下方、卡片内部。

Events

事件名载荷说明
update:modelValuestring查询文本变化。
queryChangestring同上,供不使用 v-model 的宿主监听。
selectSearchPanelItem结果被点击或 Enter 选中。
clear-通过清除按钮或 Esc 清空。

Exposed

名称说明
focus() / blur()聚焦、失焦输入框。
clear()清空查询并派发 clear

交互契约

  • 键盘导航是补齐的能力,上游完全没有。 ↑ ↓ 在两端循环并跳过禁用项,Home / End 跳到首尾可用项,Enter 选中当前高亮项,Esc 在有内容时清空。输入法组合期间的 Enter 被忽略(同时判定 isComposingcompositionstart / compositionend),不会把候选词确认误当成选中。
  • ARIA 走 combobox 范式:输入框是 role="combobox" + aria-autocomplete="list" + aria-controls + aria-activedescendant,列表是 role="listbox",每行是 role="option"tabindex="-1"——焦点始终留在输入框,Tab 会离开整个部件而不是逐行穿过。
  • 高亮态是 is-active 而不是 :hover:只靠 hover 的话键盘用户看不到光标在哪。鼠标移动会把高亮同步到指针所在行。
  • 选中结果不会把文案写回输入框。 上游会写回,那是为了让 demo 自洽;对命令列表而言,写回等于把"执行命令"变成了"重命名查询"。宿主收到 select 后自行决定。

最佳实践

  • 用作命令面板时,select 里执行动作并清空查询;用作筛选器时保留查询,让用户看得见当前条件。
  • 远端搜索传 filter="items => items" 关掉内建匹配,监听 queryChange 自己防抖取数,否则服务端结果会被再过滤一次。
  • 把同义词放进 keywords 而不是塞进 label:既能命中又不会让标题变长。
  • 不可用的项传 disabled 而不是从 items 里删掉——保留它并置灰,用户才知道这个能力存在。
  • minHeight 按最长常见结果数设定;设得太小会退回它本要消除的跳动。

Source

  • Component source: packages/tuffex/packages/components/src/search-panel/src/TxSearchPanel.vue
  • Types: packages/tuffex/packages/components/src/search-panel/src/types.ts
  • Composes: packages/tuffex/packages/components/src/search-empty/src/TxSearchEmpty.vue
  • 实测覆盖: packages/tuffex/packages/components/src/search-panel/__tests__/search-panel.test.ts 验证空查询短清单与实时过滤、keywords 参与匹配、filter 覆盖、双通道派发查询与清空、空态阈值、combobox/listbox 全套 ARIA、方向键两端循环与 Home/End、禁用项跳过且拒绝选中、Enter 选中且不回写输入框、输入法组合期忽略 Enter、Esc 仅在有内容时清空,以及预留高度与 focus()
  • 改编自 Beautiful UI,© 2026 Shane Levine,MIT 协议。
查看源码
packages/tuffex/packages/components/src/search-panel/index.ts