DOM 节点的克隆与删除

无奈的开头

        关于DOM节点操作,如果仅仅是根据标准API来操作,那是最简单不过的了。但是现实中却哪有这么容易的问题让我们解决,其实不仅仅是节点的克隆与删除,节点的添加也是如此,而且添加节点需要考虑的情况更多,这里不详细讲解,只说明大概过程。

        问题那么多,主要出现在浏览器自身实现上,其中尤属legacy IE上—IE6,7,8. 在添加节点的API实现上,IE做了一个贡献,那就是insertAdjacentHTML函数被纳入HTML5规范上,这个函数在之前的文章中详细讲解并实现过,不提。此后,IE的行为却不值得提倡,因为我们的兼容性主要针对的就是legacy IE。

        克隆节点,规范的API是cloneNode(boolean),boolean为true时进行深克隆。但是legacy IE却有一个奇怪的bug,那就是通过该方法克隆的副本,却仍含有相关的事件处理函数和用户自定义属性,而且修改删除这些属性或者函数,会影响到源节点的属性生病。。。着实让人无语。解决方案另辟蹊径,即可以通过获取副本的HTML字符串,重新构造一个DOM节点,这样根据字符串反系列化的副本就不会包含在js中额外操作的属性或者事件处理程序。

         删除节点理应没有什么问题,但是legacy IE下仅仅使用removeNode会出现内存泄露问题,被删除的节点有部分内存并不会被回收,如果长时间运行该程序,则可能会出现内存耗尽的危险,只有关闭页面才可能回收这些内存。但是可以利用outerHTML属性做文章,他可以更有效的删除占用的内存,但是需要注意的是这种方法仍然不会完全释放占用的内存,但是总体回收的内存大于removeNode方法。

实现

    /**
           * 旧版IE(IE678)拷贝元素节点,会连同事件处理函数和用户自定义属性一同拷贝给
             * 副本,并且修改副本的事件处理函数和自定义属性会影响到源节点。
             */
            clone =  function(){
                // 如果是IE678下的bug
                var el,c;
                if(Screen.support.cloneNodeWithHandler){
                    el = this[0].cloneNode(true);
                    c = doc.createElement("div");
                    c.appendChild(el);
                    return S.DomParser(c.innerHTML).firstChild;
                }else{
                    return this.cloneNode(true);
                }
            }
            remove =  function(){
                this.each(function(el){
                    if(el.nodeType && el.nodeType == 1){
                        S._unData(el);
                        if(el.parentNode){
                            el.parentNode.removeChild(el);
                        }
                        // IE 678下这样会造成内存泄露,元素节点删除之后
                        // 仍有部分内存不能回收。可通过outerHTML回收,但是
                        // 需要知道的是这种方法也不能回收节点使用的全部内存,但是
                        // 最起码回收的比removeChild多。
                        if(typeof el.outerHTML !== undefined){
                            el.outerHTML = "";
                        }
                    }
                });
                return this;
            }

 

上述代码是本人私人库实现的一部分,有错误之处还请指出。

 

 

 

    

posted @ 2015-01-20 21:42  royalrover  阅读(1117)  评论(1编辑  收藏  举报