update id map when DOM changed and handle element scroll event

This commit is contained in:
Yanzhen Yu
2026-04-01 12:00:00 +08:00
parent a90198ee46
commit c9bb0e6557
4 changed files with 27 additions and 22 deletions

2
.gitignore vendored
View File

@@ -3,3 +3,5 @@ node_modules
package-lock.json package-lock.json
build build
dist dist
temp

View File

@@ -1,5 +1,5 @@
import record from './record'; import record from './record';
import replay from './replay'; import { Replayer } from './replay';
import { mirror } from './utils'; import { mirror } from './utils';
export { record, replay, mirror }; export { record, Replayer, mirror };

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
import { rebuild } from 'rrweb-snapshot'; import { rebuild, serializeNodeWithId } from 'rrweb-snapshot';
import later from './timer'; import later from './timer';
import { import {
EventType, EventType,
@@ -8,12 +8,9 @@ import {
eventWithTime, eventWithTime,
MouseInteractions, MouseInteractions,
} from '../types'; } from '../types';
import eventsStr from './events';
import { mirror, getIdNodeMap } from '../utils'; import { mirror, getIdNodeMap } from '../utils';
const _events: eventWithTime[] = JSON.parse(eventsStr); export class Replayer {
class Replayer {
private events: eventWithTime[] = []; private events: eventWithTime[] = [];
private wrapper: HTMLDivElement; private wrapper: HTMLDivElement;
private iframe: HTMLIFrameElement; private iframe: HTMLIFrameElement;
@@ -90,7 +87,8 @@ class Replayer {
this.iframe.contentDocument!.open(); this.iframe.contentDocument!.open();
// https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML // https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
this.iframe.contentDocument!.write( this.iframe.contentDocument!.write(
(doc as Document).documentElement.outerHTML new XMLSerializer()
.serializeToString(doc as Document)
.replace(/&/g, '&') .replace(/&/g, '&')
.replace(/&lt;/g, '<') .replace(/&lt;/g, '<')
.replace(/&gt;/g, '>'), .replace(/&gt;/g, '>'),
@@ -124,11 +122,11 @@ class Replayer {
} }
} }
}); });
// TODO: update id node map
d.removes.forEach(mutation => { d.removes.forEach(mutation => {
const target = (mirror.getNode(mutation.id) as Node) as Element; const target = (mirror.getNode(mutation.id) as Node) as Element;
const parent = (mirror.getNode(mutation.parentId) as Node) as Element; const parent = (mirror.getNode(mutation.parentId) as Node) as Element;
parent.removeChild(target); parent.removeChild(target);
delete mirror.map[mutation.id];
}); });
d.adds.forEach(mutation => { d.adds.forEach(mutation => {
const target = (mirror.getNode(mutation.id) as Node) as Element; const target = (mirror.getNode(mutation.id) as Node) as Element;
@@ -144,6 +142,11 @@ class Replayer {
} else { } else {
parent.appendChild(target); parent.appendChild(target);
} }
serializeNodeWithId(
mirror.getNode(mutation.id),
this.iframe.contentDocument!,
mirror.map,
);
}); });
break; break;
} }
@@ -168,14 +171,20 @@ class Replayer {
} }
break; break;
} }
case IncrementalSource.Scroll: case IncrementalSource.Scroll: {
// TODO: maybe element const target = mirror.getNode(d.id) as Node;
this.iframe.contentWindow!.scrollTo({ if (target === this.iframe.contentDocument) {
top: d.y, this.iframe.contentWindow!.scrollTo({
left: d.x, top: d.y,
behavior: 'smooth', left: d.x,
}); behavior: 'smooth',
});
} else {
(target as Element).scrollTop = d.y;
(target as Element).scrollLeft = d.x;
}
break; break;
}
case IncrementalSource.ViewportResize: case IncrementalSource.ViewportResize:
this.iframe.width = `${d.width}px`; this.iframe.width = `${d.width}px`;
this.iframe.height = `${d.height}px`; this.iframe.height = `${d.height}px`;
@@ -192,7 +201,3 @@ class Replayer {
} }
} }
} }
const replayer = new Replayer(_events);
export default replayer;