如何在使用较小的标识符时唯一标识 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 对于变化,需要标明操作类型,可以是attribute
,inserted
,或者removed
,对于removed
的情况,可以马上发送要抓取的路径,在本例中为 paths.get(node)
.
我希望这些细节有用,因为你要做的事情很复杂,但并非不可能,我不会为你编写整个软件,因为这不是本网站的目的
P.S. 字面意思是 所有 节点路径,您可能还想在 record.addedNodes
,因此对于每个添加的节点,您需要抓取其所有 childNodes
并这样做,直到所有 childNodes
都被映射。这不会很快,但它会让您能够通知页面上的每个通用节点。
我正在做一个项目,两个浏览器应该同步它们的 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)
.
但是,变异观察者不会告诉你的是,每当它的记录填充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 对于变化,需要标明操作类型,可以是attribute
,inserted
,或者removed
,对于removed
的情况,可以马上发送要抓取的路径,在本例中为 paths.get(node)
.
我希望这些细节有用,因为你要做的事情很复杂,但并非不可能,我不会为你编写整个软件,因为这不是本网站的目的
P.S. 字面意思是 所有 节点路径,您可能还想在 record.addedNodes
,因此对于每个添加的节点,您需要抓取其所有 childNodes
并这样做,直到所有 childNodes
都被映射。这不会很快,但它会让您能够通知页面上的每个通用节点。