Files
rrweb/src/record/observer.ts
2026-04-01 12:00:00 +08:00

108 lines
2.7 KiB
TypeScript

import { INode } from 'rrweb-snapshot';
import { mirror } from '../utils';
import {
mutationCallBack,
textMutation,
attributeMutation,
removedNodeMutation,
addedNodeMutation,
observerParam,
} from '../types';
function initMutationObserver(cb: mutationCallBack): MutationObserver {
const observer = new MutationObserver(mutations => {
const texts: textMutation[] = [];
const attributes: attributeMutation[] = [];
const removes: removedNodeMutation[] = [];
const adds: addedNodeMutation[] = [];
mutations.forEach(mutation => {
const {
type,
target,
oldValue,
addedNodes,
removedNodes,
attributeName,
nextSibling,
previousSibling,
} = mutation;
const id = mirror.getId(target as INode);
switch (type) {
case 'characterData': {
const value = target.textContent;
if (value !== oldValue) {
texts.push({
id,
value,
});
}
break;
}
case 'attributes': {
const value = (target as HTMLElement).getAttribute(attributeName!);
if (value === oldValue) {
return;
}
let item: attributeMutation | undefined = attributes.find(
a => a.id === id,
);
if (!item) {
item = {
id,
attributes: {},
};
attributes.push(item);
}
// overwrite attribute if the mutations was triggered in same time
item.attributes[attributeName!] = value;
}
case 'childList': {
removedNodes.forEach(n => {
removes.push({
parentId: id,
id: mirror.getId(n as INode),
});
});
addedNodes.forEach(n => {
adds.push({
parentId: id,
previousId: !previousSibling
? previousSibling
: mirror.getId(previousSibling as INode),
nextId: !nextSibling
? nextSibling
: mirror.getId(nextSibling as INode),
id: mirror.getId(n as INode),
});
});
break;
}
default:
break;
}
});
cb({
texts,
attributes,
removes,
adds,
});
});
observer.observe(document, {
attributes: true,
attributeOldValue: true,
characterData: true,
characterDataOldValue: true,
childList: true,
subtree: true,
});
return observer;
}
export default function initObservers(o: observerParam) {
const mutationObserver = initMutationObserver(o.mutationCb);
return {
mutationObserver,
};
}