Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,9 @@ replayer.pause();

// pause at the fifth seconds
replayer.pause(5000);

// destroy the replayer (hint: this operation is irreversible)
replayer.destroy();
```

#### Options
Expand Down Expand Up @@ -385,6 +388,7 @@ The event list:
| mouse-interaction | mouse interaction has been replayed | { type, target } |
| event-cast | event has been replayed | event |
| custom-event | custom event has been replayed | event |
| destroy | destroyed the replayer | - |

The rrweb-replayer also re-expose the event listener via a `component.addEventListener` API.

Expand Down
4 changes: 4 additions & 0 deletions guide.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ replayer.pause();

// 暂停至第 5 秒处
replayer.pause(5000);

// 销毁播放器 (提示: 这个操作不可逆)
replayer.destroy();
```

#### 配置参数
Expand Down Expand Up @@ -384,6 +387,7 @@ replayer.on(EVENT_NAME, (payload) => {
| mouse-interaction | 回放鼠标交互事件 | { type, target } |
| event-cast | 回放 event | event |
| custom-event | 回放自定义事件 | event |
| destroy | 销毁播放器 | - |

使用 `rrweb-player` 时,也可以通过 `addEventListener` API 使用相同的事件功能,并且会获得 3 个额外的事件:

Expand Down
29 changes: 21 additions & 8 deletions packages/rrweb/src/replay/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ export class Replayer {
this.rebuildFullSnapshot(
firstFullsnapshot as fullSnapshotEvent & { timestamp: number },
);
this.iframe.contentWindow!.scrollTo(
this.iframe.contentWindow?.scrollTo(
(firstFullsnapshot as fullSnapshotEvent).data.initialOffset,
);
}, 1);
Expand Down Expand Up @@ -433,12 +433,22 @@ export class Replayer {

public resume(timeOffset = 0) {
console.warn(
`The 'resume' will be departed in 1.0. Please use 'play' method which has the same interface.`,
`The 'resume' was departed in 1.0. Please use 'play' method which has the same interface.`,
);
this.play(timeOffset);
this.emitter.emit(ReplayerEvents.Resume);
}

/**
* Totally destroy this replayer and please be careful that this operation is irreversible.
* Memory occupation can be released by removing all references to this replayer.
*/
public destroy() {
this.pause();
this.config.root.removeChild(this.wrapper);
this.emitter.emit(ReplayerEvents.Destroy);
}

public startLive(baselineTime?: number) {
this.service.send({ type: 'TO_LIVE', payload: { baselineTime } });
}
Expand Down Expand Up @@ -582,7 +592,7 @@ export class Replayer {
this.firstFullSnapshot = true;
}
this.rebuildFullSnapshot(event, isSync);
this.iframe.contentWindow!.scrollTo(event.data.initialOffset);
this.iframe.contentWindow?.scrollTo(event.data.initialOffset);
};
break;
case EventType.IncrementalSnapshot:
Expand All @@ -603,6 +613,7 @@ export class Replayer {
}
if (this.isUserInteraction(_event)) {
if (
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
_event.delay! - event.delay! >
SKIP_TIME_THRESHOLD *
this.speedService.state.context.timer.speed
Expand All @@ -614,6 +625,7 @@ export class Replayer {
}
if (this.nextUserInteractionEvent) {
const skipTime =
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.nextUserInteractionEvent.delay! - event.delay!;
const payload = {
speed: Math.min(
Expand Down Expand Up @@ -734,7 +746,7 @@ export class Replayer {
styleEl,
getDefaultSN(styleEl, this.virtualDom.unserializedId),
);
(documentElement as RRElement)!.insertBefore(styleEl, head as RRElement);
(documentElement as RRElement).insertBefore(styleEl, head as RRElement);
for (let idx = 0; idx < injectStylesRules.length; idx++) {
// push virtual styles
styleEl.rules.push({
Expand All @@ -745,12 +757,12 @@ export class Replayer {
}
} else {
const styleEl = document.createElement('style');
(documentElement as HTMLElement)!.insertBefore(
(documentElement as HTMLElement).insertBefore(
styleEl,
head as HTMLHeadElement,
);
for (let idx = 0; idx < injectStylesRules.length; idx++) {
styleEl.sheet!.insertRule(injectStylesRules[idx], idx);
styleEl.sheet?.insertRule(injectStylesRules[idx], idx);
}
}
}
Expand Down Expand Up @@ -984,6 +996,7 @@ export class Replayer {
doAction() {
//
},
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
delay: e.delay! - d.positions[0]?.timeOffset,
});
}
Expand Down Expand Up @@ -1721,14 +1734,14 @@ export class Replayer {
}
const sn = this.mirror.getMeta(target);
if (target === this.iframe.contentDocument) {
this.iframe.contentWindow!.scrollTo({
this.iframe.contentWindow?.scrollTo({
top: d.y,
left: d.x,
behavior: isSync ? 'auto' : 'smooth',
});
} else if (sn?.type === NodeType.Document) {
// nest iframe content document
(target as Document).defaultView!.scrollTo({
(target as Document).defaultView?.scrollTo({
top: d.y,
left: d.x,
behavior: isSync ? 'auto' : 'smooth',
Expand Down
1 change: 1 addition & 0 deletions packages/rrweb/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,7 @@ export enum ReplayerEvents {
Flush = 'flush',
StateChange = 'state-change',
PlayBack = 'play-back',
Destroy = 'destroy',
}

export type KeepIframeSrcFn = (src: string) => boolean;
Expand Down
17 changes: 17 additions & 0 deletions packages/rrweb/test/replayer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -687,4 +687,21 @@ describe('replayer', function () {

await assertDomSnapshot(page);
});

it('should destroy the replayer after calling destroy()', async () => {
await page.evaluate(`events = ${JSON.stringify(events)}`);
await page.evaluate(`
const { Replayer } = rrweb;
let replayer = new Replayer(events);
replayer.play();
`);

const replayerWrapperClassName = 'replayer-wrapper';
let wrapper = await page.$(`.${replayerWrapperClassName}`);
expect(wrapper).not.toBeNull();

await page.evaluate(`replayer.destroy(); replayer = null;`);
wrapper = await page.$(`.${replayerWrapperClassName}`);
expect(wrapper).toBeNull();
});
});