要将单向 DOM-1 复制到 DOM-2,您可以在 DOM-1 中使用 document MutationObserver,它会通知您:
- 每个节点的属性更改
- 已删除的节点
- 已添加的节点
- 已移动的节点,通过组合先前通知的顺序
如果 DOM-1 和 DOM-2 从一开始就相同,那么在 DOM-1 中唯一映射节点并在 DOM-2 中寻址的简单方法如下:
const {indexOf} = [];
const nodePath = node => {
const path = [];
let parentElement;
// crawl up to the document.documentElement
while (parentElement = node.parentElement) {
path.push(indexOf.call(parentElement.childNodes, node));
node = parentElement;
}
return path;
};
const findNode = path => path.reduceRight(
// crawl down from the document.documentElement
(parentElement, i) => parentElement.childNodes[i],
document.documentElement
);
在 DOM-1 中,您可以通过 const path = nodePath(anyNode) 找到它,您可以通过 findNode(path) 在 DOM-2 中找到它。
然而,突变观察者不会告诉你的是,只要它的记录填充removedNodes 列表,就是这些节点已从中删除。 p>
为了规避这个限制,您需要在 DOM-1 中,并且可能通过 WeakMap 存储文档中附加的所有节点,以便您始终可以将更改传播到 DOM- 2.
// the most top script on the page (at least in DOM-1)
const paths = new WeakMap;
new MutationObserver(records => {
for (const record of records) {
for (const node of record.addedNodes)
paths.set(node, nodePath(node));
}
}).observe(document, {childList: true, subtree: true});
现在,每当 other 泛型 MutationObserver 负责通知,通过 Web 套接字或其他任何东西,DOM-2 进行更改时,您需要通知操作类型,可以是attribute、inserted或removed,对于removed的情况,您可以立即发送要抓取的路径,在这种情况下为paths.get(node)。
我希望这些细节有用,因为您尝试做的事情很复杂,但并非不可能,而且我不会为您编写整个软件,因为这不是本网站的目的?
P.S. 具有字面上的 所有 节点路径,您可能还希望在 record.addedNodes 中递归设置这些路径,以便每个添加的节点,您需要抓取它的所有childNodes 并这样做直到所有childNodes 都被映射。这不会很快,但它会让您能够通知页面上的每个通用节点。