检测 DOM 元素的父元素何时更改
Detecting when a DOM element's parent changes
是否有当元素的parentElement
发生变化时触发的 DOM 事件?如果没有,还有什么比轮询超时更好的方法吗?
我特别感兴趣的是知道parentElement
何时从null
更改为某个定义的元素。也就是说,当 DOM 元素附加到文档树的某个位置时。
编辑
鉴于注释中的问题,下面是一个示例,展示了如何使用null
parentElement
创建元素:
var element = document.createElement('div');
console.assert(element.parentElement == null);
父级仅在添加到 DOM 后进行设置:
document.body.appendChild(element);
console.assert(element.parentElement != null);
另请注意,使用 jQuery 创建的元素在创建时也将具有null
父元素:
console.assert($('<div></div>').get(0).parentElement == null);
Afaik 没有这样的"父侦听器"。
然而,我发现了一个可能有帮助的黑客。至少值得一读,因为这个想法很聪明。
http://www.backalleycoder.com/2012/04/25/i-want-a-damnodeinserted/
他在插入过程中使用 CSS @keyframes,并侦听生成的动画事件,该事件告诉他元素已插入。
1(这样的parentElementHasChanged event
不存在。
2(PISquared指出的解决方法可以工作,但对我来说看起来很奇怪。
3(在实践中,没有必要发生这样的事件。只有当元素在 DOM 中的位置发生变化时,parentChange 才会出现在元素上。为此,您必须在执行此操作的元素上运行一些代码,并且所有这些代码都必须使用本机parent.removeChild()
, parent.appendChild
,parent.insertBefore()
或parent.replaceChild()
某个地方。相同的代码可以在之后运行回调,因此回调将是事件。
4( 您正在构建库代码。该库可以为所有 DOM 插入/删除提供单个函数,该函数包装四个本机函数并"触发事件"。这是我想到的最后一个也是唯一一个避免频繁查找 parentElement 的方法。
5(如果需要包含本机Event API
,您可以使用CustomEvent创建一个parentChanged事件
element.addEventListener('parentChanged', handler); // only when Event API needed
function manipulateElementsDOMPosition(element, target, childIndex, callback, detail) {
if (!target.nodeType) {
if (arguments.length > 4) return element;
detail = callback; callback = childIndex; childIndex = target; target = null;
}
if (typeof childIndex === 'function') detail = callback, callback = childIndex;
var oldParent = element.parentElement,
newParent = target,
sameParent = oldParent === newParent,
children = newParent.children,
cl = children.length,
ix = sameParent && cl && [].indexOf.call(children, element),
validPos = typeof childIndex === 'number' && cl <= childIndex;
if (childIndex === 'replace') {
(newParent = target.parentElement).replaceChild(element, target);
if (sameParent) return element;
} else {
if (samePar) {
if (!oldParent || ix == childIndex ||
childIndex === 'first' && ix === 0 ||
childIndex === 'last' && ix === (cl - 1)) return element;
oldParent.removeChild(element);
} else if (oldParent) oldParent.removeChild(element);
if (!cl || childIndex === 'last') {
newParent.appendChild(element);
} else if (childIndex === 'first') {
newParent.insertBefore(element, children[0])
} else if (validPos) {
newParent.insertBefore(element, children[childIndex]);
} else return element;
}
console.log(element, 'parentElement has changed from: ', oldParent, 'to: ', newParent);
element.dispatchEvent(new CustomEvent('parentChanged', detail)); // only when Event API needed
if (typeof callback === 'function') callback.call(element, oldParent, newParent, detail);
return element;
}
一些示例用法(详细信息可能是要传递给事件/回调的任何内容(。函数始终返回元素。
// remove element
manipulateElementsDOMPosition(element /*optional:*/, callback, detail);
// prepend element in target
manipulateElementsDOMPosition(element, target, 'first' /*optional:*/, callback, detail);
// append element in target
manipulateElementsDOMPosition(element, target, 'last' /*optional:*/, callback, detail);
// add element as third child of target, do nothing when less than two children there
manipulateElementsDOMPosition(element, target, 3 /*optional:*/, callback, detail);
// replace a target-element with element
manipulateElementsDOMPosition(element, target, 'replace' /*optional:*/, callback, detail);
你可以像这样使用MutationObserver:
const trackedElement = document.getElementById('tracked-element');
const parent1 = document.getElementById('parent1');
const parent2 = document.getElementById('parent2');
startObserver();
function changeParent() {
if (trackedElement.parentElement == parent1) {
parent1.removeChild(trackedElement);
parent2.appendChild(trackedElement);
} else {
parent2.removeChild(trackedElement);
parent1.appendChild(trackedElement);
}
}
function startObserver() {
let parentElement = trackedElement.parentElement
new MutationObserver(function(mutations) {
if (!parentElement.contains(trackedElement)) {
trackedElement.textContent = "Parent changed";
setTimeout(() => {
trackedElement.textContent = "Parent not changed";
}, 500);
startObserver();
this.disconnect();
}
}).observe(parentElement, {
childList: true
});
}
<!doctype html>
<html lang="en">
<body>
<div id="parent1">
<p id="tracked-element">Parent not changed</p>
</div>
<div id="parent2"></div>
<button onclick="changeParent()">ChangeParent</button>
</body>
</html>
您可以右键单击Parent not changed
文本,然后单击检查以确保它确实正在更改父项
如果你想知道.observer
函数是如何工作的,这里有非常好的文档:https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe
- 使用Underscore.js修改json数组中所选元素的更有效方法
- 何时更喜欢javascript中的匿名函数
- D3 - 如何确定元素何时离开屏幕
- 观察任何元素何时更改
- Js-一种在DOM中查找第n个元素的更优雅/更有效的方法
- 如何知道元素何时滚动到底
- 滚动后,检测元素何时返回到原始位置
- 在javascript中更新多个元素的更有效方法
- 如何知道指令的最后一个元素何时在 AngularJS 中链接
- 从指令包装源元素的更好方法
- 合成 JavaScript 元素何时执行
- 如何让getElementsByClassName针对所有标记的元素-还有更好的替代方案吗
- 检查对象、函数或元素何时准备就绪
- 检查coffeescript中最后一个元素的更好方法
- 如何在JavaScript中检测一个元素何时覆盖另一个元素
- JQuery:检测元素和所有子元素何时加载
- 我如何知道DOM“body”元素何时可用
- 我如何判断HTML5音频元素何时播放完毕
- 在元素中查找元素的更好方法
- 检测 DOM 元素的父元素何时更改