> ## Documentation Index
> Fetch the complete documentation index at: https://dripart-docs-recommend-assets-api.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 带注释的示例

不断增长的示例代码片段集合……

## 右键菜单

### 背景菜单

主背景菜单（在画布上右键）是通过调用 `LGraphCanvas.getCanvasMenuOptions` 生成的。标准的编辑方式是在扩展上实现 `getCanvasMenuItems` 方法：

```javascript theme={null}
app.registerExtension({
  name: "MyExtension",
  getCanvasMenuItems(canvas) {
    const items = []
    items.push(null) // 插入分隔线
    items.push({
      content: "菜单的文本",
      callback: async () => {
        // 执行任意操作
      }
    })
    return items
  }
});
```

### 节点菜单

当你在节点上右键时，菜单同样是通过 `node.getExtraMenuOptions` 生成的。
标准的方式是在扩展上实现 `getNodeMenuItems` 方法：

```javascript theme={null}
app.registerExtension({
  name: "MyExtension",
  getNodeMenuItems(node) {
    const items = []

    // 如果需要，你可以按节点类型过滤
    if (node.comfyClass === "MyNodeClass") {
      items.push({
        content: "做点有趣的事",
        callback: async () => {
          // 有趣的操作
        }
      })
    }

    return items
  }
});
```

### 子菜单

如果你想要子菜单，使用带有 `options` 数组的 `submenu` 属性：

```javascript theme={null}
app.registerExtension({
  name: "MyExtension",
  getCanvasMenuItems(canvas) {
    const items = []
    items.push({
      content: "带选项的菜单",
      submenu: {
        options: [
          {
            content: "选项 1",
            callback: (v) => {
              // 用 v 做点什么
            }
          },
          {
            content: "选项 2",
            callback: (v) => {
              // 用 v 做点什么
            }
          },
          {
            content: "选项 3",
            callback: (v) => {
              // 用 v 做点什么
            }
          }
        ]
      }
    })
    return items
  }
});
```

## 捕获 UI 事件

这和你预期的一样——在 DOM 中找到 UI 元素并添加 eventListener。`setup()` 是做这件事的好地方，因为此时页面已完全加载。例如，检测"队列"按钮的点击：

```Javascript theme={null}
function queue_button_pressed() { console.log("队列按钮被按下！") }
document.getElementById("queue-button").addEventListener("click", queue_button_pressed);
```

## 检测工作流开始

这是众多 `api` 事件之一：

```javascript theme={null}
import { api } from "../../scripts/api.js";
/* 在 setup() 中 */
    function on_execution_start() { 
        /* 执行任意操作 */
    }
    api.addEventListener("execution_start", on_execution_start);
```

## 检测工作流被中断

<Note>
  **已弃用：** 下面展示的 API 劫持模式已被弃用，可能在不久的将来随时更改。请尽可能使用官方的 [扩展钩子](/zh/custom-nodes/js/javascript_hooks) 和 API 事件监听器。
</Note>

这是一个劫持 api 的简单例子：

```Javascript theme={null}
import { api } from "../../scripts/api.js";
/* 在 setup() 中 */
    const original_api_interrupt = api.interrupt;
    api.interrupt = function () {
        /* 在调用原方法前做点什么 */
        original_api_interrupt.apply(this, arguments);
        /* 或者在之后 */
    }
```

## 捕获节点点击

<Note>
  **已弃用：** 下面展示的节点方法劫持模式已被弃用，可能在不久的将来随时更改。请尽可能使用官方的 [扩展钩子](/zh/custom-nodes/js/javascript_hooks)。
</Note>

`node` 有一个 mouseDown 方法可以被劫持。
这次我们注意传递任何返回值。

```javascript theme={null}
async nodeCreated(node) {
    if (node?.comfyClass === "My Node Name") {
        const original_onMouseDown = node.onMouseDown;
        node.onMouseDown = function( e, pos, canvas ) {
            alert("哎呦！");
            return original_onMouseDown?.apply(this, arguments);
        }        
    }
}
```
