feat: add a destroy function to destroy the whole player (#953)
* feat: add a destroy function to destroy the whole player * doc: update guidance document * Update packages/rrweb/src/replay/index.ts Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com> Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>
This commit is contained in:
4
guide.md
4
guide.md
@@ -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
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -276,6 +276,9 @@ replayer.pause();
|
||||
|
||||
// 暂停至第 5 秒处
|
||||
replayer.pause(5000);
|
||||
|
||||
// 销毁播放器 (提示: 这个操作不可逆)
|
||||
replayer.destroy();
|
||||
```
|
||||
|
||||
#### 配置参数
|
||||
@@ -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 个额外的事件:
|
||||
|
||||
|
||||
@@ -322,7 +322,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);
|
||||
@@ -441,12 +441,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 deprecated 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 } });
|
||||
}
|
||||
@@ -590,7 +600,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:
|
||||
@@ -611,6 +621,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
|
||||
@@ -622,6 +633,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(
|
||||
@@ -742,7 +754,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({
|
||||
@@ -753,12 +765,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -992,6 +1004,7 @@ export class Replayer {
|
||||
doAction() {
|
||||
//
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
delay: e.delay! - d.positions[0]?.timeOffset,
|
||||
});
|
||||
}
|
||||
@@ -1708,14 +1721,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',
|
||||
|
||||
@@ -743,6 +743,7 @@ export enum ReplayerEvents {
|
||||
Flush = 'flush',
|
||||
StateChange = 'state-change',
|
||||
PlayBack = 'play-back',
|
||||
Destroy = 'destroy',
|
||||
}
|
||||
|
||||
export type KeepIframeSrcFn = (src: string) => boolean;
|
||||
|
||||
@@ -701,4 +701,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();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user