如何在使用较小的标识符时唯一标识 DOM 元素

How to uniquely identify DOM elements while using little size for the identifier

我正在做一个项目,两个浏览器应该同步它们的 DOM 元素。每当 DOM 元素在一个浏览器上发生更改时,只有更改和更改元素的位置会通过 websocket 发送到另一个浏览器。

为了让它工作,我需要一种方法来为更改的元素提供一个唯一标识符,该标识符使用少量大小,而其他浏览器应该能够找到更改元素的位置。

对此有什么好的方法?

要将单向 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列表时,是这些节点已从中删除。

为了规避此限制,您需要在 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 对于变化,需要标明操作类型,可以是attributeinserted,或者removed,对于removed的情况,可以马上发送要抓取的路径,在本例中为 paths.get(node).

我希望这些细节有用,因为你要做的事情很复杂,但并非不可能,我不会为你编写整个软件,因为这不是本网站的目的

P.S. 字面意思是 所有 节点路径,您可能还想在 record.addedNodes,因此对于每个添加的节点,您需要抓取其所有 childNodes 并这样做,直到所有 childNodes 都被映射。这不会很快,但它会让您能够通知页面上的每个通用节点。