【问题标题】:Element reference breaks on modification of innerHTML property of container修改容器的 innerHTML 属性时元素引用中断
【发布时间】:2011-08-24 08:19:35
【问题描述】:
在通过代码创建元素时,我遇到了一个问题,即修改元素的 innerHTML 属性会破坏对在修改之前注入到被修改元素中的其他元素的任何引用。
我在这里有一个测试用例:http://jsfiddle.net/mJ7bF/1/,我希望link1 引用的行为与link2 完全相同。
第二个测试用例是相同的代码,但不是使用innerHTML 属性来添加<br> 标记,而是使用一个对象创建换行符。此测试按预期运行:http://jsfiddle.net/K4c9a/2/
我的问题不是关于这个特定的代码,而是它背后的概念:在第一个测试用例中 link1 引用会发生什么?如果它不引用在将cont 节点注入文档时可见的 HTML/DOM 节点,它指的是什么,以及这与 javascript 对象的 ByReference 特性有何关系?
【问题讨论】:
标签:
javascript
dom
object
mootools
pass-by-reference
【解决方案1】:
这里有几件事。
首先。字符串是不可变的,因此 element.innerHTML += "<br>" 相当于一个完整的读取和重写。
其次,为什么不好:
除了性能之外,mootools(和 jquery,就此而言)为所有引用的元素分配特殊的唯一顺序 uid。您可以通过在其上调用选择器或创建它等来引用元素。
然后考虑带有uid 的特定元素说5。uid 链接到一个名为Storage 的特殊对象,该对象位于闭包后面(因此它是私有的)。它有 uid 作为键。
元素存储然后在element.store("key", value") 和element.retrieve("key") 上工作
最后,为什么这很重要:events 被存储到元素存储中(例如,Storage[5]['events']) - 执行 element.retrieve("events") 并在 fireBug 中进行探索,如果你是好奇的。
当你重写 innerHTML 时,旧元素不再存在。然后重新创建它,但事件处理程序和对您之前绑定的函数的引用将不再起作用,因为它现在将获得一个新的uid。
就是这样,希望它有意义。
要添加 br,只需执行 new Element("br").inject(element) 或为批次创建模板片段(最快)并添加 1 个大块,然后添加事件。
【解决方案2】:
HTML 在内部由 DOM 对象结构表示。有点像传统编程语言中的 Tree 类。如果设置innerHTML,则父节点中的先前节点被销毁,新的innerHTML被解析,并创建新的对象。引用不再相同。
div
|-- a..
上面的 div 对象包含一个 Anchor 对象作为子对象。现在设置一个变量 link1 作为对这个 Anchor 对象地址的引用。那么.innerHTML就是+= "<br />",表示所有div的节点都被移除,根据.innerHTML新值的解析结果动态重新创建。现在旧的引用不再有效,因为 Anchor 标记被重新创建为一个新的对象实例。