我的代码的简化版本:
<div id="d">text<br><hr>text</div>
<script>
// Called when DOM changes.
function mutationCallback(mutations) {
// assert(mutations.length === 3);
var insertImg = mutations[0];
console.log(insertImg.previousSibling.parentNode); // Null!
console.log(insertImg.nextSibling.parentNode); // Null!
// Can't determine where img was inserted!
}
// Setup
var div = document.getElementById('d');
var br = div.childNodes[1];
var hr = div.childNodes[2];
var observer = new MutationObserver(mutationCallback);
observer.observe(div, {childList: true, subtree: true});
// Trigger DOM Changes.
var img = document.createElement('img');
div.insertBefore(img, hr);
div.removeChild(hr);
div.removeChild(br); // mutationCallback() is first called after this line.
</script>
我正在使用 Mutation Observers 来捕获 DOM 更改,以便在一个文档实例发生变化时更新另一个文档实例。因为直到 的前一个和下一个兄弟被移除后才会调用突变观察器函数,所以 mutationCallback 函数无法判断它插入的位置。转载于 Chrome、FF 和 IE11。
另一种方法是遍历整个文档以查找更改,但这会抵消使用 Mutation Observers 的性能优势。
最佳答案
mutations
数组是针对特定目标发生的突变的完整列表。这意味着,对于任意元素,了解父元素在发生该突变时的唯一方法是您必须查看后来的突变以查看父元素何时发生突变,例如
var target = mutations[0].target
var parentRemoveMutation = mutations
.slice(1)
.find(mutation => mutation.removedNodes.indexOf(target) !== -1);
var parentNode = parentRemoveMutation
? parentRemoveMutation.target // If the node was removed, that target is the parent
: target.parentNode; // Otherwise the existing parent is still accurate.
不过如您所见,这是针对第一个突变进行的硬编码,您可能必须一次对列表中的每个项目执行一次。这不会很好地扩展,因为它必须进行线性搜索。您还可以通过完整的突变列表来首先构建该元数据。
总而言之,这里问题的核心似乎是您真的不应该关心理想世界中的 parent 。例如,如果您正在同步两个文档,您可以考虑使用 WeakMap
来跟踪元素,因此对于每个可能的元素,都有一个从正在变异的文档到同步文档中的每个元素的映射。然后当发生突变时,您可以只使用 Map 在原始文档中查找相应的元素,并在原始文档上重现更改,而无需查看父文档。
关于javascript - MutationObserver 的 DOM 上下文丢失,因为它触发得太晚,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49263285/