---
title: "useSigmaSearch"
description: "按属性检索节点与边，结果随图变更自动重算，可把相机聚焦到命中项。"
canonical_url: "https://sigma.mhaibaraai.cn/docs/composables/use-sigma-search"
---
# useSigmaSearch

> 按属性检索节点与边，结果随图变更自动重算，可把相机聚焦到命中项。

## 用法

`query` 可双向绑定，`results` 随检索词与图变更自动重算：

```vue [UseSigmaSearchExample.vue]
<script setup lang="ts">
import type { StylesDeclaration } from 'sigma/types'

const { data: dataset } = await useFetch('/api/wikipedia.json', { server: false })

const styles = computed<StylesDeclaration>(() => ({
  nodes: {
    color: { attribute: 'cluster', dict: dataset.value?.clusterColors ?? {}, defaultValue: '#94a3b8' },
    size: {
      attribute: 'score',
      min: 4,
      max: 18,
      minValue: dataset.value?.scoreExtent[0],
      maxValue: dataset.value?.scoreExtent[1]
    }
  },
  edges: { color: '#e2e8f0' }
}))
</script>

<template>
  <SigmaGraph
    v-if="dataset"
    :data="dataset.data"
    :styles="styles"
    :settings="{ hideEdgesOnMove: true }"
  >
    <UseSigmaSearchPanel />
  </SigmaGraph>
</template>
```

```vue [UseSigmaSearchPanel.vue]
<script setup lang="ts">
const { query, results, focus } = useSigmaSearch()
</script>

<template>
  <input v-model="query">
  <button v-for="result in results" :key="result.id" type="button" @click="focus(result)">
    {{ result.label }}
  </button>
</template>
```

需要开箱即用的完整检索框（防抖、键盘导航、命中高亮），用 [`SigmaSearchControl`](https://sigma.mhaibaraai.cn/docs/components/search-control)；这个 composable 是它的底座，适合自己设计交互时用。

### `fields`

参与匹配的属性名。只有**字符串**类型的属性值参与匹配，数字、布尔、对象一律跳过；匹配是子串、大小写不敏感，**不做模糊匹配**也不支持正则。

按顺序取第一个命中的字段作展示，结果里的 `label` 与 `field` 就来自它，所以字段顺序有意义：把最适合展示的放在前面。

```vue [UseSigmaSearchFieldsExample.vue]
<script setup lang="ts">
const props = defineProps<{ fields: string, edges: boolean }>()

const fieldList = computed(() => props.fields.split('+'))

const { data } = await useFetch('/api/data.json')
</script>

<template>
  <SigmaGraph :data="data">
    <UseSigmaSearchFieldsPanel :key="`${fields}-${edges}`" :fields="fieldList" :edges="edges" />
  </SigmaGraph>
</template>
```

### `limit`

结果条数上限，节点与边**共享**这一个上限：节点先填满时，边一条都不会被扫到。

它只截断结果，**不截断遍历**——达到上限后回调仍会为剩余的每个元素执行一次（只是提前返回）。控制的是渲染量，不是扫描成本。

### `edges`

是否同时检索边。结果次序固定：所有节点命中在前，边命中在后，各自内部落到 graphology 的迭代顺序上。

## 示例

### 不建索引

匹配在内存里做。`graph.forEachNode` 遍历万级节点是毫秒量级，而维护索引要处理图变更的同步，得不偿失。

> [!WARNING]
> 
> **没有内置防抖。** `results` 是计算属性，`query` 每变一次就全量重扫一遍。直接把它绑到输入框上，万级图会卡输入——请自己加防抖：
> 
> ```ts
> const input = shallowRef('')
> const { query, results } = useSigmaSearch()
> 
> watchDebounced(input, value => query.value = value, { debounce: 200 })
> ```

### 聚焦

`focus()` 把相机移到命中项上，动画时长硬编码 `300` 毫秒。边没有单一位置，解析到 `graph.source(edge)`。命中项已不在图上、或尚未渲染出显示数据时静默返回。

需要自定义动画参数就别用它，改调 [`useSigmaCamera().gotoNode()`](https://sigma.mhaibaraai.cn/docs/composables/use-sigma-camera)：

```ts
await gotoNode(result.id, { duration: 600, ratio: 0.4 })
```

## API

### useSigmaSearch()

`useSigmaSearch(options?: UseSigmaSearchOptions): UseSigmaSearchReturn`

#### Options

**fields** (`string[]`): 默认 ['label'] —— 参与匹配的属性名，按顺序取第一个命中的作展示。

**limit** (`number`): 默认 20 —— 结果条数上限，节点与边共享。只截断结果，不截断遍历。

**edges** (`boolean`): 默认 false —— 是否同时检索边。边命中排在全部节点命中之后。

#### Returns

**query** (`Ref<string>`): 检索词，可双向绑定。空串或全空白时结果为空数组。

**results** (`ComputedRef<SigmaSearchResult[]>`): 命中结果，随检索词与图变更重算。

**focus()** (`(result: SigmaSearchResult) => Promise<void>`): 相机聚焦到某条结果，动画时长为 300 毫秒。目标不存在时静默返回。

### SigmaSearchResult

**type** (`'node' | 'edge'`): 命中的图元类型。

**id** (`string`): 节点或边的 key。用 id 而非 key，后者是 Vue 的保留属性。

**label** (`string`): 用于展示的文本，取自命中的字段。

**field** (`string`): 命中所在的属性名。

类型从根出口取：

```ts
import type { SigmaSearchResult, UseSigmaSearchOptions, UseSigmaSearchReturn } from '@movk/sigma'
```


## Sitemap

See the full [sitemap](https://sigma.mhaibaraai.cn/sitemap.md) for all pages.
