---
title: "主题事件"

doc_type: static
doc_category: static
doc_version: v20270301
source_url:
  html: 'https://developer.shopline.com/zh-hans-cn/docs/online-store-3-0-themes/best-practice/theme-events'
  md: 'https://developer.shopline.com/zh-hans-cn/docs/online-store-3-0-themes/best-practice/theme-events.md'
---
# 主题事件
主题事件是一种用于主题模块与模块之间或者主题模块与应用之间通信的机制。通过 [事件构造器](#LQ92G) 构建的事件对象和 [事件总线](#FHA69) 提供的接口，你能够在主题模块或者应用中，触发或者接收特定场景的事件。

---


## 事件总线{#FHA69}
事件总线是信息传输的枢纽，你可以通过事件总线发布 [主题事件](#E4OpP)，也可以通过事件总线订阅感兴趣的事件，事件总线负责将事件通知给订阅者，能有效解耦模块，提升系统的可维护性与扩展性。

在 [Bottle](https://developer.shopline.com/zh-hans-cn/docs/online-store-3-0-themes/bottle.md) 主题里，会在全局对象 `window` 下注入一个事件总线，你可以通过 `window.themeEventCenter` 获取到事件总线。


### 接口{#rEHdJ}
事件总线提供了如下接口，让你能够轻松发布和订阅事件。


#### dispatch{#yf0wr}
触发指定事件

`.dispatch(event: ThemeEvent): void`

<h5 id="pgZn4"></h5>
##### 参数
| 参数名 | 参数类型 | 必填 | 描述 |
| --- | --- | --- | --- |
| event | ThemeEvent | 是 | 事件对象实例。你可以创建自定义事件对象实例，或者创建 [标准事件](#E4OpP) 对象实例。 |


<h5 id="GCgX9"></h5>
##### 返回值
无

<h5 id="Wka2S"></h5>
##### 代码示例
以下是通过事件总线触发 [商品浏览事件](#xfPur) 的代码示例：

```javascript
window.themeEventCenter.dispatch(
  new ThemeEvent('product:viewed', {
    detail: {
      productId: '16069825781843611825520845',
      productHandle: 'Shirt',
      variantId: '18066825256105052042503900',
      price: 9999,
      currency: 'USD'
    }
  })
);
```


#### addListener{#lUILN}
监听指定事件

`.addListener(eventName: string, callback: (event: Event) => void): EventListener`

<h5 id="nf1kp"></h5>
##### 参数
| 参数名 | 参数类型 | 必填 | 描述 |
| --- | --- | --- | --- |
| eventName | string | 是 | 事件名称。你可以创建自定义事件名称，或者使用 [标准事件](#E4OpP) 名称。 |
| callback | func | 是 | 事件触发时的回调函数。该函数通常接受一个参数 `event` 事件，你可以通过 `event.detail` 获取对应的事件对象数据，具体数据结构可参考 [创建事件对象](#HudrF)。 |


<h5 id="dPJl4"></h5>
##### 返回值
一个 `EventListener` 事件监听器对象，携带以下字段：

| 参数名 | 参数类型 | 描述 |
| --- | --- | --- |
| eventName | string | 监听的事件名称 |
| remove | func | 移除事件监听方法 |


<h5 id="CKhNF"></h5>
##### 代码示例
以下是通过事件总线监听 [商品浏览事件](#xfPur) 的代码示例：

```javascript
window.themeEventCenter.addListener('product:viewed', (event) => {
  console.log(event.id);
  console.log(event.target);
  console.log(event.detail.productId);
});
```

#### getCurrentDetail{#l88se}
获取指定事件最近一次触发时携带的 `detail` 数据

`.getCurrentDetail(eventName: string): Record<string, any> | undefined`

<h5 id="KYJt8"></h5>
##### 参数
| 参数名 | 参数类型 | 必填 | 描述 |
| --- | --- | --- | --- |
| eventName | string | 是 | 事件名称。 |


<h5 id="y2eUK"></h5>
##### 返回值
对应事件的 `detail` 数据

<h5 id="qbaNa"></h5>
##### 代码示例
以下是通过事件总线获取 [商品浏览事件](#xfPur) 触发后，该商品数据的代码示例：

```javascript
const viewProduct = window.themeEventCenter.getCurrentDetail('product:viewed');

console.log(viewProduct?.productId); // 输出商品 ID
```

---


## 事件构造器{#LQ92G}
事件构造器是用于创建事件对象的工具，它能定义事件的类型、携带的数据及相关属性。你可灵活配置事件，为事件赋予特定行为和特征，方便在不同场景触发和传递。

在 [Bottle](https://developer.shopline.com/zh-hans-cn/docs/online-store-3-0-themes/bottle.md) 主题里，会在全局对象 `window` 下注入一个事件构造器，你可以通过 `window.ThemeEvent` 获取到事件构造器。


### 创建事件对象{#HudrF}
你可以通过 `new ThemeEvent` 创建一个事件对象

`new ThemeEvent(eventName: string, eventInitDict: EventInit)`


#### 参数{#faEoT}
<table>
<tr>
  <th>
    参数名
  </th>
  <th>
    参数类型
  </th>
  <th>
    必填
  </th>
    <th>
    描述
    </th>
</tr>
<tr>
  <td>
eventName
  </td>
  <td>
 string
  </td>
  <td>
是
  </td>
    <td>
        事件名称
    </td>
</tr>
<tr>
  <td>
  eventInitDict
  </td>
  <td>
EventInit
  
  </td>
    <td>
        是
    </td>
   
<td>
    事件初始化数据。`EventInit` 的参数如下所示：<br/>
    - `id`（可选）：显式声明事件的唯一标识，该标识会传递给 [事件监听器](#lUILN) ，不传则自动生成唯一标识。<br/>
    - `target`（可选）：显式声明事件的触发来源 DOM 节点。<br/>
    - `detail`（必选）：事件携带的相关数据，事件监听器可以通过 `Event.detail` 获取。
    
**标准数据如下所示:**
    ```typescript 
    interface EventInit {   
      id?: string;   
      target?: Element; 
      detail: Record<string, any> 
    } 
    ```  
  </td>

</tr>
</table>



#### 返回值{#HSKn6}
事件对象 ThemeEvent


#### 代码示例{#vsson}
以下是创建一个商品浏览事件对象的代码示例：

```javascript
new ThemeEvent('product:view', {
  detail: {
    ...
  }
});
```

### 标准事件{#E4OpP}
事件构造器支持以下几种标准事件类型：


#### 商品浏览{#xfPur}
事件名：product: viewed

触发时机：进入商品详情页、打开快速加购弹窗或单个商品组件展示时触发

<h5 id="iWzn3"></h5>
##### 标准数据
```typescript
interface Detail {
  productId: string;			// 商品 ID
  productHandle: string;	// 商品 handle
  variantId?: string;			// 商品 SKU ID，当主题配置不默认选中商品 SKU 时，将返回空值
  price?: number;					// 商品 SKU 价格，当主题配置不默认选中商品 SKU 时，将返回空值
  currency: string;				// 结算币种
}
```

<h5 id="rWjTd"></h5>
##### 代码示例
```javascript
// 触发事件
window.themeEventCenter.dispatch(
  new ThemeEvent('product:viewed', {
    detail: {
      productId: '16069825781843611825520845',
      productHandle: 'Shirt',
      variantId: '18066825256105052042503900',
      price: 9999,
      currency: 'USD'
    }
  })
);


// 监听事件
window.themeEventCenter.addListener('product:viewed', (event) => {
  console.log(event.detail.productId); // 输出商品 ID
});
```


#### 商品 SKU 切换{#TxGML}
事件名：variant: changed

触发时机：商品详情页、快速加购弹窗或单个商品组件中切换 SKU 时触发

<h5 id="Ai7dR"></h5>
##### 标准数据
```typescript
interface Detail {
  productId: string;			// 商品 ID
  productHandle: string;	// 商品 handle
  variantId: string;			// 商品 SKU ID
  quantity: number;				// 商品 SKU 数量
  price: number;					// 商品 SKU 价格
  currency: string;				// 结算币种
}
```

<h5 id="LiTZg"></h5>
##### 代码示例
```javascript
// 触发事件
window.themeEventCenter.dispatch(
  new ThemeEvent('variant:changed', {
    detail: {
      productId: '16069825781843611825520845',
      productHandle: 'Shirt',
      variantId: '18066825256105052042503900',
      quantity: 1,
      price: 9999,
      currency: 'USD'
    }
  })
);


// 监听事件
window.themeEventCenter.addListener('variant:changed', (event) => {
  console.log(event.detail.variantId); // 输出商品 SKU ID
});
```


#### 商品 SKU 加购{#yvUfD}
事件名：variant: added

触发时机：添加商品到购物车时触发

<h5 id="cMtc8"></h5>
##### 标准数据
```typescript
interface Detail {
  lineItemKey: string;		// 购物车项标识
  productId: string;			// 商品 ID
  productHandle: string;	// 商品 handle
  variantId: string;			// 商品 SKU ID
  quantity: number;				// 商品 SKU 数量
  price: number;					// 商品 SKU 价格，当主题配置不默认选中商品 SKU 时，将返回空值
  currency: string;				// 结算币种
}
```

<h5 id="Afj2Z"></h5>
##### 代码示例
```javascript
// 触发事件
window.themeEventCenter.dispatch(
  new ThemeEvent('variant:added', {
    detail: {
      productId: '16069825781843611825520845',
      productHandle: 'Shirt',
      variantId: '18066825256105052042503900',
      quantity: 1,
      price: 9999,
      currency: 'USD',
      lineItemKey: '18064578594821059446022470:430512ac683d4903983eeee3c168ade8'
    }
  })
);


// 监听事件
window.themeEventCenter.addListener('variant:added', (event) => {
  // 输出商品 SKU ID 和商品 SKU 数量
  console.log(event.detail.variantId, event.detail.quantity);
});
```

<h4 id="L6Cy0"></h4>
#### 购物车已打开
事件名：cart: opened

触发时机：打开购物车时触发

<h5 id="GI824"></h5>
##### 标准数据
```typescript
interface Detail {
  type: 'notification' | 'drawer';	// 购物车类型
}
```

<h5 id="N8RXz"></h5>
##### 代码示例
```javascript
// 触发事件
window.themeEventCenter.dispatch(
  new ThemeEvent('cart:opened', {
    detail: {
      type: 'drawer'
    }
  })
);


// 监听事件
window.themeEventCenter.addListener('cart:opened', (event) => {
  const { detail } = event;
  console.log('购物车已打开', detail.type);
});
```

<h4 id="SZ5NN"></h4>
#### 购物车已关闭
事件名：cart: closed

触发时机：关闭购物车时触发

<h5 id="OIGXU"></h5>
##### 标准数据
```typescript
interface Detail {
  type: 'notification' | 'drawer';	// 购物车类型
}
```

<h5 id="DpqS2"></h5>
##### 代码示例
```javascript
// 触发事件
window.themeEventCenter.dispatch(
  new ThemeEvent('cart:closed', {
    detail: {
      type: 'drawer'
    }
  })
);


// 监听事件
window.themeEventCenter.addListener('cart:closed', (event) => {
  const { detail } = event;
  console.log('购物车已关闭', detail.type);
});
```

<h4 id="iZ5u8"></h4>
#### 打开购物车
事件名：cart: open

触发时机：触发打开购物车动作，调用方无需关心主题配置及实现，由主题自行注册行为的实现。

<h5 id="gklbK"></h5>
##### 标准数据
```typescript
interface Detail {
  refresh?: boolean; // 是否刷新购物车内容，默认为 false
}
```

<h5 id="e7qsr"></h5>
##### 代码示例
```javascript
// 触发“打开购物车”事件
window.themeEventCenter.dispatch(
  new ThemeEvent('cart:open', {
    detail: {
      refresh: true	// 刷新购物车
    }
  })
);


// 主题代码，监听“打开购物车”事件，并实现具体业务逻辑
window.themeEventCenter.addListener('cart:open', (event) => {
  // 获取传递过来的参数
  const { refresh } = event.detail;
  
  // 获取最近添加的商品数据
  const addedVariantDetail = themeEventCenter.getCurrentDetail('variant:added');

  // 输出商品 ID
  console.log(addedVariantDetail.productId);
});
```

<h4 id="dyH1J"></h4>
#### 打开快速加购弹窗
事件名：quick-add: open

触发时机：触发打开快速加购弹窗动作，一般需要商品加购时调用。

<h5 id="mwjTi"></h5>
##### 标准数据
```typescript
interface Detail {
  productHandle: string; // 商品 handle
}
```

<h5 id="jUnza"></h5>
##### 代码示例
```javascript
// 触发“打开快速加购弹窗”事件
window.themeEventCenter.dispatch(
  new ThemeEvent('quick-add:open', {
    detail: {
      productHandle: 'Shirt'
    }
  })
);
```

> **warning**
>
> **注意**：监听 “打开快速加购弹窗” 事件的实现逻辑，已由官方内置，主题开发者无需实现。
