2014-09-18 86 views
1

元素的parentElement更改时是否会触发DOM事件?如果没有,有没有比超时轮询更好的方法?检测DOM元素的父元素更改

我在知道何时parentElementnull更改为某个定义的元素时特别感兴趣。也就是说,当某个DOM元素附加到文档树的某处时。

编辑

鉴于该评论的问题,在这里展示了如何创建一个带有nullparentElement元素的例子:

var element = document.createElement('div'); 

console.assert(element.parentElement == null); 

一旦它加入到父只设置DOM:

document.body.appendChild(element); 

console.assert(element.parentElement != null); 

请注意,使用jQuery创建的元素将会使用al创建时等有null父:

console.assert($('<div></div>').get(0).parentElement == null); 
+0

您试图聆听一个元素是否被另一个元素包裹? – enguerranws 2014-09-18 15:54:10

+2

如果孩子已经在DOM中,parentElement如何可以为null?我在这里错过了什么吗? – Krumia 2014-09-18 15:55:16

+1

是的,这也是我的问题,所有元素都至少将html元素作为父元素? – enguerranws 2014-09-18 15:56:28

回答

3

AFAIK有没有这样的“父听众”。

但是,我发现一个可能有用的黑客攻击。至少这是值得一读的,因为这个想法很聪明。

http://www.backalleycoder.com/2012/04/25/i-want-a-damnodeinserted/

他使用插入时CSS @keyframes并监听生成的动画事件,告诉他,该元素得到了插入。

+1

请在此处添加该外部资源的摘要,否则当该页面死亡(而不是'如果')时,您的答案立即变得无用。 – 2014-09-18 21:03:04

+0

感谢您的回答。这绝对是一个有趣的想法。不得不求助于此虽然是一种耻辱。欢迎来到SO btw :) – 2014-09-18 22:12:49

1

1)这样的parentElementHasChanged event不存在。

2)解决方法PISquared指向将工作,但对我来说看起来很奇怪。

3)实际上不需要这样的事件。一个parentChange只会出现在一个元素,如果它在DOM变化中的位置。要做到这一点,你必须在这个元素上运行一些代码,并且所有代码必须使用本地parent.removeChild(), parent.appendChild,parent.insertBefore()parent.replaceChild()某处。之后相同的代码可以运行回调,所以回调将是事件。

4)您正在构建库代码。该库可以为所有的DOM插入/删除提供一个单一的函数,它包装了四个原生函数并“触发事件”。这是我脑海中最后也是唯一避免频繁查找parentElement的内容。

5)如果有需要包括本地Event API,您可以创建一个parentChanged事件与CustomEvent

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);