---
title: "SigmaContextMenu"
description: "右键节点、边或空白处弹出的菜单，自动压掉浏览器原生菜单。"
canonical_url: "https://sigma.mhaibaraai.cn/docs/components/context-menu"
---
# SigmaContextMenu

> 右键节点、边或空白处弹出的菜单，自动压掉浏览器原生菜单。

## 用法

右键节点、边或画布空白处弹出菜单，并在接管的目标上压掉浏览器原生菜单。点击节点或画布空白处关闭，插槽作用域里也带了 `close`，供菜单项执行完自行收起。

### `target`

数组，决定右键哪里会弹菜单，默认只接管 `['node']`，`'stage'` 即空白处：

```vue [ContextMenuTargetExample.vue]
<script setup lang="ts">
withDefaults(defineProps<{ target?: Array<'node' | 'edge' | 'stage'> }>(), {
  target: () => ['node']
})

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

<template>
  <SigmaGraph :data="data" :settings="{ enableEdgeEvents: true }">
    <SigmaContextMenu :target="target">
      <template #default="{ type, id }">
        <span class="text-xs">{{ type }} {{ id ?? '（空白处）' }}</span>
      </template>
    </SigmaContextMenu>
  </SigmaGraph>
</template>
```

节点与边的命中锚定到节点（边取 `graph.source(edge)`），走 framed 坐标换算；空白处命中没有节点可锚，组件把视口坐标转成图坐标后交给 `SigmaOverlay` 的 `position` 通道，走原始图坐标换算。两条路径的结果一致，作用域里的字段则有区别，见下面的插槽小节。

> [!WARNING]
> 
> target
> 
>  含 
> 
> 'edge'
> 
>  时，必须先在 
> 
> settings
> 
>  里开 
> 
> enableEdgeEvents: true
> 
> ，否则边上的右键事件根本不会触发。

### `offset`

相对锚点的像素偏移，默认 `[4, 4]`。菜单**没有** CSS `translate`，左上角就落在锚点上，从光标右下方展开，`offset` 只是留出一点间隙：

```vue [ContextMenuOffsetExample.vue]
<script setup lang="ts">
const props = withDefaults(defineProps<{
  offsetX?: number | string
  offsetY?: number | string
}>(), {
  offsetX: 4,
  offsetY: 4
})

const offset = computed<[number, number]>(() => [Number(props.offsetX), Number(props.offsetY)])

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

<template>
  <SigmaGraph :data="data">
    <SigmaContextMenu :offset="offset">
      <template #default="{ attributes }">
        <span class="text-xs">{{ attributes.label }} 的菜单</span>
      </template>
    </SigmaContextMenu>
  </SigmaGraph>
</template>
```

## 示例

### 默认插槽

插槽以 `{ id, type, attributes, close }` 暴露命中项。`type` 为 `'stage'` 时 `id` 为 `null`、`attributes` 为 `{}`，菜单项通常是「在此处新建节点」这类与具体图元无关的操作：

```vue [ContextMenuSlotExample.vue]
<script setup lang="ts">
const last = shallowRef('')

const { data } = await useFetch('/api/small.json')

function run(action: string, close: () => void) {
  last.value = action
  close()
}
</script>

<template>
  <SigmaGraph :data="data" :settings="{ enableEdgeEvents: true }">
    <SigmaContextMenu :target="['node', 'edge', 'stage']">
      <template #default="{ id, type, attributes, close }">
        <div class="flex min-w-35 flex-col gap-1.5">
          <span class="text-muted text-xs">{{ type }} {{ id ?? '（空白处）' }}</span>
          <UButton
            v-if="type === 'stage'"
            size="xs"
            variant="ghost"
            color="neutral"
            label="在此处新建节点"
            @click="run('在此处新建节点', close)"
          />
          <UButton
            v-else
            size="xs"
            variant="ghost"
            color="neutral"
            :label="`打开「${attributes.label ?? id}」`"
            @click="run(`打开 ${attributes.label ?? id}`, close)"
          />
        </div>
      </template>
    </SigmaContextMenu>
  </SigmaGraph>
</template>
```

> [!NOTE]
> 
> 键名用 
> 
> id
> 
>  而非 
> 
> key
> 
> ，后者是 Vue 的保留属性。
> 
> attributes
> 
>  在图元已被移除时同样是 
> 
> {}
> 
> 。

### 压掉原生菜单

`event.preventSigmaDefault()` 只拦 sigma 自己的默认行为，浏览器菜单照样弹出。所幸 sigma 的鼠标捕获器直接监听 DOM 的 `contextmenu` 且没有调用 `preventDefault()`，而事件处理函数是在那个监听器里同步执行的——于是组件在此把原生事件一并拦下：

```ts
function take(event: MouseCoords) {
  event.preventSigmaDefault()
  event.original.preventDefault()
}
```

这件事只在**确实接管的目标**上做。`target` 里没写 `'stage'` 时，在空白处右键仍然弹浏览器自己的菜单，不影响「在图上右键另存为图片」这类原生能力——上面 `target` 那节的示例里去掉 `stage` 就能试出来。

## API

### Props

```ts
/**
 * Props for the SigmaContextMenu component
 */
interface SigmaContextMenuProps {
  /**
   * 响应的图元类型。`stage` 即空白处右键
   * @default ["node"]
   */
  target?: ("node" | "edge" | "stage")[] | undefined;
  /**
   * 相对锚点的像素偏移 `[x, y]`
   * @default [4, 4]
   */
  offset?: [number, number] | undefined;
}
```

### Slots

```ts
/**
 * Slots for the SigmaContextMenu component
 */
interface SigmaContextMenuSlots {
  default(): any;
}
```

### Expose

通过 [`useTemplateRef`](https://vuejs.org/api/composition-api-helpers.html#usetemplateref) 访问类型化的组件实例。

| Name | Type |
| --- | --- |
| `close()` | `() => void` <br> 关闭菜单，与插槽作用域里的同名方法一致。 |


## Sitemap

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