# 搜索框组件

一个专为搜索功能设计的文本输入组件，内置搜索图标并优化了输入处理。支持国际化文本输入的组合事件处理和清除功能。

## 安装

```bash
npm install @ticatec/uniface-element
```

## 导入

```typescript
import SearchBox from "@ticatec/uniface-element/SearchBox";
```

## 基本用法

```svelte
<script>
  import SearchBox from "@ticatec/uniface-element/SearchBox";
  
  let searchQuery = '';
  
  function handleSearch(query) {
    console.log('搜索：', query);
  }
</script>

<SearchBox 
  bind:value={searchQuery} 
  onchange={handleSearch}
  placeholder="搜索..."
/>
```

## 属性

| 属性 | 类型 | 默认值 | 描述 |
|------|------|---------|-------------|
| `value` | `string \| null` | 必需 | 当前搜索输入值 |
| `onchange` | `OnChangeHandler<string \| null>` | `null` | 输入值更改（失焦/回车）时的回调函数 |
| `oninput` | `OnChangeHandler<string \| null>` | `null` | 输入值实时更改时的回调函数 |
| `onfocus` | `((event: FocusEvent) => void) \| null` | `null` | 输入框获得焦点时的回调函数 |
| `onblur` | `((event: FocusEvent) => void) \| null` | `null` | 输入框失去焦点时的回调函数 |
| `disabled` | `boolean` | `false` | 输入框是否禁用 |
| `placeholder` | `string \| null` | `null` | 占位符文本 |
| `variant` | `"" \| "plain" \| "outlined" \| "filled"` | `""` | 输入框的视觉变体 |
| `compact` | `boolean` | `false` | 是否使用紧凑间距 |
| `style` | `string` | `""` | 附加 CSS 样式 |

## 方法

| 方法 | 描述 |
|--------|-------------|
| `focus()` | 以编程方式使搜索输入框获得焦点 |

## 示例

### 基本搜索

```svelte
<script>
  import SearchBox from "@ticatec/uniface-element/SearchBox";
  
  let searchTerm = '';
  let results = [];
  
  function performSearch(query) {
    if (query) {
      // 模拟搜索
      results = [`"${query}" 的结果 1`, `"${query}" 的结果 2`];
    } else {
      results = [];
    }
  }
</script>

<SearchBox 
  bind:value={searchTerm}
  onchange={performSearch}
  placeholder="搜索产品..."
/>

{#if results.length > 0}
  <ul>
    {#each results as result}
      <li>{result}</li>
    {/each}
  </ul>
{/if}
```

### 实时搜索

```svelte
<script>
  import SearchBox from "@ticatec/uniface-element/SearchBox";
  import { debounce } from 'lodash-es';
  
  let searchQuery = '';
  let suggestions = [];
  
  // 防抖搜索函数
  const debouncedSearch = debounce((query) => {
    if (query.length > 2) {
      // 模拟 API 调用
      suggestions = [
        `${query} 建议 1`,
        `${query} 建议 2`,
        `${query} 建议 3`
      ];
    } else {
      suggestions = [];
    }
  }, 300);
  
  function handleInput(query) {
    debouncedSearch(query);
  }
</script>

<SearchBox 
  bind:value={searchQuery}
  oninput={handleInput}
  placeholder="输入以搜索..."
/>

{#if suggestions.length > 0}
  <div class="suggestions">
    {#each suggestions as suggestion}
      <div class="suggestion-item">{suggestion}</div>
    {/each}
  </div>
{/if}

<style>
  .suggestions {
    border: 1px solid #ddd;
    border-radius: 4px;
    margin-top: 4px;
  }
  
  .suggestion-item {
    padding: 8px 12px;
    cursor: pointer;
  }
  
  .suggestion-item:hover {
    background-color: #f5f5f5;
  }
</style>
```

### 带事件处理程序

```svelte
<script>
  import SearchBox from "@ticatec/uniface-element/SearchBox";
  
  let searchValue = '';
  let isSearching = false;
  
  function handleChange(query) {
    console.log('搜索确认：', query);
    // 执行最终搜索
  }
  
  function handleInput(query) {
    console.log('输入更改：', query);
    // 实时建议
  }
  
  function handleFocus(event) {
    console.log('搜索框已聚焦');
    isSearching = true;
  }
  
  function handleBlur(event) {
    console.log('搜索框已失焦');
    isSearching = false;
  }
</script>

<SearchBox 
  bind:value={searchValue}
  onchange={handleChange}
  oninput={handleInput}
  onfocus={handleFocus}
  onblur={handleBlur}
  placeholder="搜索..."
/>

{#if isSearching}
  <p>搜索进行中...</p>
{/if}
```

### 不同变体

```svelte
<script>
  import SearchBox from "@ticatec/uniface-element/SearchBox";
  
  let search1 = '', search2 = '', search3 = '';
</script>

<!-- 默认变体 -->
<SearchBox bind:value={search1} placeholder="默认搜索" />

<!-- 轮廓变体 -->
<SearchBox bind:value={search2} variant="outlined" placeholder="轮廓搜索" />

<!-- 填充变体 -->
<SearchBox bind:value={search3} variant="filled" placeholder="填充搜索" />
```

### 紧凑模式

```svelte
<script>
  import SearchBox from "@ticatec/uniface-element/SearchBox";
  
  let compactSearch = '';
</script>

<div class="toolbar">
  <SearchBox 
    bind:value={compactSearch} 
    compact 
    placeholder="快速搜索" 
  />
</div>

<style>
  .toolbar {
    display: flex;
    align-items: center;
    padding: 8px;
    background: #f8f9fa;
  }
</style>
```

### 带过滤器的搜索

```svelte
<script>
  import SearchBox from "@ticatec/uniface-element/SearchBox";
  import Button from "@ticatec/uniface-element/Button";
  
  let searchTerm = '';
  let filterType = 'all';
  let items = [
    { name: '苹果 iPhone', category: 'electronics' },
    { name: '耐克鞋', category: 'clothing' },
    { name: '咖啡机', category: 'appliances' },
    { name: '三星电视', category: 'electronics' }
  ];
  
  $: filteredItems = items.filter(item => {
    const matchesSearch = !searchTerm || 
      item.name.toLowerCase().includes(searchTerm.toLowerCase());
    const matchesFilter = filterType === 'all' || 
      item.category === filterType;
    return matchesSearch && matchesFilter;
  });
  
  function clearSearch() {
    searchTerm = '';
  }
</script>

<div class="search-controls">
  <SearchBox 
    bind:value={searchTerm}
    placeholder="搜索产品..."
    style="flex: 1; margin-right: 8px;"
  />
  <Button label="清除" onClick={clearSearch} />
</div>

<div class="filters">
  <label>
    <input type="radio" bind:group={filterType} value="all" />
    全部
  </label>
  <label>
    <input type="radio" bind:group={filterType} value="electronics" />
    电子产品
  </label>
  <label>
    <input type="radio" bind:group={filterType} value="clothing" />
    服装
  </label>
</div>

<div class="results">
  {#each filteredItems as item}
    <div class="item">{item.name} - {item.category}</div>
  {/each}
</div>

<style>
  .search-controls {
    display: flex;
    margin-bottom: 16px;
  }
  
  .filters {
    display: flex;
    gap: 16px;
    margin-bottom: 16px;
  }
  
  .item {
    padding: 8px;
    border-bottom: 1px solid #eee;
  }
</style>
```

### 禁用状态

```svelte
<script>
  import SearchBox from "@ticatec/uniface-element/SearchBox";
  
  let searchValue = '';
  let isDisabled = false;
</script>

<label>
  <input type="checkbox" bind:checked={isDisabled} />
  禁用搜索
</label>

<SearchBox 
  bind:value={searchValue}
  disabled={isDisabled}
  placeholder="启用时可搜索..."
/>
```

### 编程式焦点

```svelte
<script>
  import SearchBox from "@ticatec/uniface-element/SearchBox";
  import Button from "@ticatec/uniface-element/Button";
  
  let searchBox;
  let searchValue = '';
  
  function focusSearch() {
    searchBox.focus();
  }
</script>

<Button label="聚焦搜索" onClick={focusSearch} />

<SearchBox 
  bind:this={searchBox}
  bind:value={searchValue}
  placeholder="点击按钮聚焦我"
/>
```

## 功能

- **搜索图标**：内置搜索图标，提供清晰的视觉提示
- **清除功能**：当输入框中有文本时自动显示清除按钮
- **组合事件**：支持国际化文本输入（IME 支持）
- **实时输入**：分别处理输入和更改事件
- **焦点管理**：支持编程式焦点控制和事件处理
- **灵活样式**：支持多种视觉变体和自定义样式选项

## 输入处理

搜索框组件提供复杂的输入处理：

1. **实时更新**：每次按键触发 `oninput` 回调
2. **确认更改**：失焦或按回车键触发 `onchange` 回调
3. **组合支持**：正确处理国际化语言的 IME 输入
4. **清除操作**：清除时触发输入和更改回调

## 行为

1. **输入**：实时更新触发 `oninput` 回调
2. **回车/失焦**：确认更改触发 `onchange` 回调
3. **清除按钮**：当输入框有文本时显示，点击时清除输入
4. **焦点**：通过点击或 Tab 键聚焦，可通过 `focus()` 方法编程控制
5. **IME 输入**：组合事件防止多键输入期间的过早更新

## 可访问性

- 为搜索功能提供适当的 ARIA 属性
- 支持键盘导航
- 屏幕阅读器兼容
- 焦点指示器和管理
- 清除按钮的可访问性

## 最佳实践

1. **搜索反馈**：在搜索操作期间提供视觉反馈
2. **防抖**：对实时搜索使用防抖以避免过多 API 调用
3. **空状态**：优雅处理空搜索结果
4. **加载状态**：为异步搜索显示加载指示器
5. **清除操作**：始终提供清除搜索的方法
6. **占位符文本**：使用描述性的占位符文本

## 浏览器支持

- 支持组合事件的现代浏览器
- 兼容 Svelte 5+
- 支持国际化输入法编辑器（IME）
- 触控友好界面

## 相关组件

- `TextEditor` - 不带搜索功能的基本文本输入
- `PromptsTextEditor` - 带建议下拉菜单的文本输入
- `LookupEditor` - 带搜索和选择功能的高级查找
- `OptionsSelect` - 带搜索功能的下拉选择