> ## Documentation Index
> Fetch the complete documentation index at: https://docs.li.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Widget Light 事件

> 使用 @lifi/widget-light 订阅 widget 事件

Widget Light 提供了一套类型化的事件系统，让你可以对用户交互、路由执行进度、钱包变化等做出响应。事件通过 `postMessage` 从 widget iframe 转发到你的主机应用。

## 订阅事件

使用 `useWidgetLightEvents()` 钩子获取事件发射器，然后用 `on` 订阅、用 `off` 取消订阅：

```tsx theme={"system"}
import {
  useWidgetLightEvents,
  WidgetLightEvent,
} from '@lifi/widget-light'
import { useEffect } from 'react'

function TransactionTracker() {
  const events = useWidgetLightEvents()

  useEffect(() => {
    const onCompleted = (data: unknown) => {
      console.log('Route completed:', data)
    }
    events.on(WidgetLightEvent.RouteExecutionCompleted, onCompleted)
    return () => {
      events.off(WidgetLightEvent.RouteExecutionCompleted, onCompleted)
    }
  }, [events])

  return null
}
```

### 关键细节

* **模块级单例** -- 事件总线是一个模块级单例，因此 `useWidgetLightEvents()` 可以从任何组件调用。它不需要与 `<LiFiWidgetLight>` 放在一起，也不需要任何 provider 包裹。

* **按订阅跟踪的转发** -- 只有当至少有一个主机端监听器订阅时，事件才会从 iframe 转发。当你调用 `events.on(eventName, handler)` 时，主机会向 iframe 发送一条 `WIDGET_EVENT_SUBSCRIBE` 消息。当某个事件的最后一个监听器被移除时，主机会发送 `WIDGET_EVENT_UNSUBSCRIBE`。这避免了不必要的 `postMessage` 流量。

* **稳定引用** -- `useWidgetLightEvents()` 返回的发射器是一个稳定的模块级对象。你无需对其进行 memoize，也无需将其添加到依赖数组中（尽管这样做是安全的）。

## 跟踪路由执行

一个常见的用例是跟踪交换或桥接路由的生命周期：

```tsx theme={"system"}
import {
  useWidgetLightEvents,
  WidgetLightEvent,
  type WidgetLightRouteExecutionUpdate,
} from '@lifi/widget-light'
import { useEffect } from 'react'

function RouteTracker() {
  const events = useWidgetLightEvents()

  useEffect(() => {
    const onStart = (data: unknown) => {
      console.log('Route started:', data)
    }
    const onUpdate = (data: WidgetLightRouteExecutionUpdate) => {
      console.log('Step updated:', data.route, data.action)
    }
    const onComplete = (data: unknown) => {
      console.log('Route completed:', data)
    }
    const onFail = (data: WidgetLightRouteExecutionUpdate) => {
      console.error('Route failed:', data.route, data.action)
    }

    events.on(WidgetLightEvent.RouteExecutionStarted, onStart)
    events.on(WidgetLightEvent.RouteExecutionUpdated, onUpdate)
    events.on(WidgetLightEvent.RouteExecutionCompleted, onComplete)
    events.on(WidgetLightEvent.RouteExecutionFailed, onFail)

    return () => {
      events.off(WidgetLightEvent.RouteExecutionStarted, onStart)
      events.off(WidgetLightEvent.RouteExecutionUpdated, onUpdate)
      events.off(WidgetLightEvent.RouteExecutionCompleted, onComplete)
      events.off(WidgetLightEvent.RouteExecutionFailed, onFail)
    }
  }, [events])

  return null
}
```

## 事件参考

### 路由执行事件

| 事件                        | Payload 类型                        | 说明                                  |
| ------------------------- | --------------------------------- | ----------------------------------- |
| `RouteExecutionStarted`   | `unknown`                         | 某个路由已开始执行                           |
| `RouteExecutionUpdated`   | `WidgetLightRouteExecutionUpdate` | 步骤进度更新（包含 `route` 和 `action`）       |
| `RouteExecutionCompleted` | `unknown`                         | 路由成功完成                              |
| `RouteExecutionFailed`    | `WidgetLightRouteExecutionUpdate` | 路由执行失败（包含 `route` 和 `action`）       |
| `RouteSelected`           | `WidgetLightRouteSelected`        | 用户选择了某个路由（包含 `route` 和 `routes` 数组） |
| `RouteHighValueLoss`      | `WidgetLightRouteHighValueLoss`   | 在某个路由上检测到高价值损失                      |

### 表单和选择事件

| 事件                              | Payload 类型                      | 说明                                               |
| ------------------------------- | ------------------------------- | ------------------------------------------------ |
| `SourceChainTokenSelected`      | `WidgetLightChainTokenSelected` | 源链/代币发生变化（包含 `chainId` 和 `tokenAddress`）         |
| `DestinationChainTokenSelected` | `WidgetLightChainTokenSelected` | 目标链/代币发生变化（包含 `chainId` 和 `tokenAddress`）        |
| `FormFieldChanged`              | `WidgetLightFormFieldChanged`   | 任何表单字段发生变化（包含 `fieldName`、`newValue`、`oldValue`） |
| `TokenSearch`                   | `WidgetLightTokenSearch`        | 用户搜索了某个代币（包含 `value` 和 `tokens`）                 |

### 钱包事件

| 事件                   | Payload 类型                      | 说明                                                                              |
| -------------------- | ------------------------------- | ------------------------------------------------------------------------------- |
| `WalletConnected`    | `WidgetLightWalletConnected`    | 钱包已连接（包含 `address`、`chainId`、`chainType`、`connectorId`、`connectorName`）         |
| `WalletDisconnected` | `WidgetLightWalletDisconnected` | 钱包已断开连接（包含 `chainType` 以及可选的 `address`、`chainId`、`connectorId`、`connectorName`） |

### UI 事件

| 事件                    | Payload 类型                  | 说明                           |
| --------------------- | --------------------------- | ---------------------------- |
| `PageEntered`         | `string`                    | 用户导航到某个页面（页面名称为字符串）          |
| `WidgetExpanded`      | `boolean`                   | widget 展开或收起（drawer 变体）      |
| `SendToWalletToggled` | `boolean`                   | 发送到钱包的开关发生变化                 |
| `AvailableRoutes`     | `unknown[]`                 | 路由已获取并可用                     |
| `ContactSupport`      | `WidgetLightContactSupport` | 用户点击了联系支持（包含可选的 `supportId`） |

### 设置和偏好事件

| 事件                            | Payload 类型                               | 说明                                                                        |
| ----------------------------- | ---------------------------------------- | ------------------------------------------------------------------------- |
| `SettingUpdated`              | `WidgetLightSettingUpdated`              | 用户更改了某项设置（包含 `setting`、`newValue`、`oldValue`、`newSettings`、`oldSettings`） |
| `ChainPinned`                 | `WidgetLightChainPinned`                 | 链被固定或取消固定（包含 `chainId` 和 `pinned`）                                        |
| `LowAddressActivityConfirmed` | `WidgetLightLowAddressActivityConfirmed` | 低活跃度地址已确认（包含 `address` 和 `chainId`）                                       |

## Payload 类型

所有 payload 类型都从 `@lifi/widget-light` 导出：

```tsx theme={"system"}
import type {
  WidgetLightRouteExecutionUpdate,
  WidgetLightRouteSelected,
  WidgetLightRouteHighValueLoss,
  WidgetLightChainTokenSelected,
  WidgetLightFormFieldChanged,
  WidgetLightWalletConnected,
  WidgetLightWalletDisconnected,
  WidgetLightContactSupport,
  WidgetLightSettingUpdated,
  WidgetLightChainPinned,
  WidgetLightTokenSearch,
  WidgetLightLowAddressActivityConfirmed,
} from '@lifi/widget-light'
```

<Note>
  携带路由的 payload（`WidgetLightRouteExecutionUpdate`、`WidgetLightRouteSelected`）对 `route` 字段使用 `unknown`，因为来自 `@lifi/sdk` 的完整路由类型在 Widget Light 的零依赖类型系统中不可用。如果你需要对路由属性进行类型化访问，请将其转换为你本地的 `@lifi/sdk` 类型。
</Note>

## WidgetLightEvent 枚举

所有事件名称都可以通过 `WidgetLightEvent` 枚举获取：

```tsx theme={"system"}
import { WidgetLightEvent } from '@lifi/widget-light'

// Use enum values for type-safe event names
events.on(WidgetLightEvent.RouteExecutionCompleted, handler)

// Or use string literals directly
events.on('routeExecutionCompleted', handler)
```

| 枚举成员                                             | 字符串值                              |
| ------------------------------------------------ | --------------------------------- |
| `WidgetLightEvent.AvailableRoutes`               | `'availableRoutes'`               |
| `WidgetLightEvent.ChainPinned`                   | `'chainPinned'`                   |
| `WidgetLightEvent.ContactSupport`                | `'contactSupport'`                |
| `WidgetLightEvent.DestinationChainTokenSelected` | `'destinationChainTokenSelected'` |
| `WidgetLightEvent.FormFieldChanged`              | `'formFieldChanged'`              |
| `WidgetLightEvent.LowAddressActivityConfirmed`   | `'lowAddressActivityConfirmed'`   |
| `WidgetLightEvent.PageEntered`                   | `'pageEntered'`                   |
| `WidgetLightEvent.RouteExecutionCompleted`       | `'routeExecutionCompleted'`       |
| `WidgetLightEvent.RouteExecutionFailed`          | `'routeExecutionFailed'`          |
| `WidgetLightEvent.RouteExecutionStarted`         | `'routeExecutionStarted'`         |
| `WidgetLightEvent.RouteExecutionUpdated`         | `'routeExecutionUpdated'`         |
| `WidgetLightEvent.RouteHighValueLoss`            | `'routeHighValueLoss'`            |
| `WidgetLightEvent.RouteSelected`                 | `'routeSelected'`                 |
| `WidgetLightEvent.SendToWalletToggled`           | `'sendToWalletToggled'`           |
| `WidgetLightEvent.SettingUpdated`                | `'settingUpdated'`                |
| `WidgetLightEvent.SourceChainTokenSelected`      | `'sourceChainTokenSelected'`      |
| `WidgetLightEvent.TokenSearch`                   | `'tokenSearch'`                   |
| `WidgetLightEvent.WidgetExpanded`                | `'widgetExpanded'`                |
| `WidgetLightEvent.WalletConnected`               | `'walletConnected'`               |
| `WidgetLightEvent.WalletDisconnected`            | `'walletDisconnected'`            |
