You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用RxJS操作符根据抽屉与物品Observable的发射调用不同方法?

问题描述

我有一个带多抽屉的柜子,每个抽屉内有可操作物品:

  • 用户切换抽屉时,Observable D 会触发;
  • 切换完成后,Observable I 会立即发射当前抽屉的物品数组,后续用户操作抽屉内物品时,I 也会持续发射事件。

流行为示例:

Drawer(D): --D----------------------------D--...
Items(I): -------I----I-----I-----I-----I----I--..

需求逻辑:

  • 每次D触发后,紧随的第一个I事件需调用setCurrentDrawerItems();
  • 在未被新的D中断时,后续所有I事件需调用userPickedItemFromDrawer()。
RxJS实现方案

这里提供两种简洁的实现方式,核心都是利用switchMap响应抽屉切换事件,同时区分当前抽屉的首次物品加载和后续用户操作:

方式一:拆分流处理

通过take(1)和skip(1)拆分I流,分别绑定对应处理函数:

import { switchMap, take, skip, merge, EMPTY } from 'rxjs';

// 假设已定义 drawer$ (Observable D) 和 items$ (Observable I)
drawer$.pipe(
  switchMap(() => {
    // 提取当前抽屉的第一个物品事件
    const initialLoad$ = items$.pipe(
      take(1),
      tap(items => setCurrentDrawerItems(items))
    );
    // 提取当前抽屉的后续用户操作事件
    const userActions$ = items$.pipe(
      skip(1),
      tap(item => userPickedItemFromDrawer(item))
    );
    // 合并两个流,用EMPTY确保仅执行副作用不发射值
    return merge(initialLoad$, userActions$).pipe(switchMap(() => EMPTY));
  })
).subscribe();

方式二:状态跟踪处理

用scan维护状态,判断是否为当前抽屉的首次I事件:

import { switchMap, scan, tap } from 'rxjs';

drawer$.pipe(
  switchMap(() => 
    items$.pipe(
      scan((isFirstLoad, items) => {
        if (isFirstLoad) {
          setCurrentDrawerItems(items);
          return false; // 首次加载完成后,状态切换为非首次
        }
        userPickedItemFromDrawer(items);
        return false;
      }, true) // 初始状态标记为首次加载
    )
  )
).subscribe();

核心逻辑说明

  • switchMap:每次drawer$触发时,会自动取消之前对items$的订阅,确保我们只处理当前抽屉的I事件,完美实现"被D中断"的要求;
  • 方式一:通过流拆分明确区分首次加载和后续操作,逻辑直观,适合需要对两类事件做额外差异化处理的场景;
  • 方式二:用scan维护状态,代码更紧凑,适合逻辑简单的场景。

内容的提问来源于stack exchange,提问作者techi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 07:55:18