该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2008-07-22
通常的解决方案是, 自行实现一套 添加事件, 移除事件 以及删除dom元素的机制. 为dom元素添加事件时, 同时记录 这个事件 以及对应的函数, 在删除dom元素时, 先移除dom元素上已经添加的事件 再删除dom元素本身. 而当页面中添加了事件监听的dom元素很多时, 移除元素变得很麻烦. 例如 一个div 里面有个form form里有多个元素都添加了事件. 那么移除这个div时, 就要先去移除他下面每一个元素上的事件 然后再移除这个div. 这种做法很多时候是必须的, 而且自己写一个"深度遍历子节点,并移除其事件"的函数也并不是很困难. 但是 在很多时候 这种做法是可以避免的, 避免的方法就是, 把事件监听注册到更上层的dom元素中. 并且在事件函数中 通过 event.target/event.srcElement 来 事件发生在哪个元素上,然后来执行相关的方法. 这样 在移除元素时 只要移除这个元素以及它上面的事件 就可以了, 而不必执行(或者少量的执行)"移除所有子节点事件"的动作了. 见下面的例子 : <table width="300" border="1" onclick="showDetail(event)"> <tr> <td>1</td> <td>Tom</td> <td><input type="button" value="详细信息" userid="1" /></td> </tr> <tr> <td>2</td> <td>Kate</td> <td><input type="button" value="详细信息" userid="2" /></td> </tr> <tr> <td>3</td> <td>John</td> <td><input type="button" value="详细信息" userid="3" /></td> </tr> </table> 在这个例子中, 实际上事件只是注册在table上, 而没有在"input type="button"上. "showDetail" 可以这样写 function showDetail_b(event) { event=event||window.event; var target=event.target||event.srcElement; if ( String(target.tagName).toLowerCase()=='input' && target.value=="详细信息") { showUserDetail(target.getAttribute('userid') ); } } 当然 这种做法不是绝对的, 有时候这么做很可能让代码变得臃肿冗长. 到底是否使用"事件上提"的做法 要根据实际情况来选择. 不过 根据我的以往经验, 在列表(table)中, 使用这种技术非常合适. 因为 列表有着"行与行之间模型一致"(只是数据不一致,结构一致)的特点. 例如,下面的效果, 都可以通过在 table上注册事件来实现: 1 点击行, 行变色 (不必在 tr 上注册点击事件) 2 点击行中的某个按钮 (不必在 tr 里的 button 上注册点击事件) 3 鼠标经过行时 行变色 (不必在 tr上注册 mouseover/mouseout 事件, 而是可以在table上注册mousemove事件) 4 还有关于单元格的 很多效果..... 当然,在非列表里 这种做法也有很多的用武之地. 总之 合理的利用"事件上提"的方法, 可以增强dom元素和事件的可控性, 有效的防止内存泄露和内存无法回收的情况. 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-07-23
这个技巧是很常见的,Prototype就为实现这个提供了不少便利,比如event.element()、element.macth('css选择符')。
关于这个有个名词,那就是“事件委托(事件代理)”,在有的情况下这还是必须的,比如,你的子元素会动态增减,那么显然单独为每个子元素设置事件那是非常浪费也非常不可取的,这个时候放到父元素上,好处就显而易见了。 |
|
返回顶楼 | |
发表时间:2008-07-23
不错,学到了一招,可以改进JavaEye的博客管理界面中在tr上的mouseover事件
|
|
返回顶楼 | |
发表时间:2008-07-23
“事件委托(事件代理)” 呵呵 笨笨狗果然是理论和实践都很牛
Quake Wang : 原来你就是 javaeye 传说中的 第三者 ??? 嘿嘿 |
|
返回顶楼 | |
发表时间:2008-07-23
好文,以前看过一篇类似的,不过比较简单,fins叙述的清晰明了。
|
|
返回顶楼 | |
发表时间:2008-07-23
引用 众所周知, 浏览器中内存泄露以及内存无法回收(两者不是一回事,很多人都把他们弄混淆了),常常是由于对dom元素注册事件不当引起的.
能否也像该文一样清晰明了的说明下呢 |
|
返回顶楼 | |
发表时间:2008-07-24
如果不在table里注册,在页面加载结束之后再对结点,再事件进行注册呢; 会有什么好与不好啊?
|
|
返回顶楼 | |
发表时间:2008-07-24
如果你愿意 一个一个元素的注册事件 在页面关闭(unload) 时再一个一个的移除这些事件
那么你的做法没什么不好的 |
|
返回顶楼 | |
发表时间:2008-07-24
to jianfeng008cn :
简单点说: 内存无法回收 : 页面内的元素或对象已经销毁,但是却没有被回收,直到刷新页面后才回收 内存泄露: 同上.但更严重的是:刷新页面之后也不回收 |
|
返回顶楼 | |
发表时间:2008-07-25
比较好奇:
在什么情况下会出現内存无法回收,什么情况下会内存泄露. |
|
返回顶楼 | |