似乎无法清理分离的DOM元素
我正在使用jquery-ui Tabs ,我遇到了删除标签时出现的问题。 该选项卡似乎与其内容div一起被删除,但当您查看Chrome DevTools配置文件中的堆(删除选项卡后)时,您将看到选项卡li和div元素仍然存在,但已分离。 随着时间的推移,重复添加/移除突片导致这些元件累积。 例如,如果添加选项卡10次,则会在堆快照中显示10个分离的div元素和10个分离的li元素:
我有以下观点:
TabLabel = Marionette.ItemView.extend({ template: "#tab-label", tagName: "li", events: { "click .ui-icon-close": "closeTab" }, closeTab: function(e) { this.$el.contents().remove(); this.model.collection.remove(this.model); $("#main-container").tabs("refresh"); this.close(); } }); TabContainer = Marionette.ItemView.extend({ template: "#tab-container", tagName: "div", onBeforeRender: function() { this.$el.attr("id", "div-" + this.id); }, onClose: function() { // This removes the region that contains the container App.layout.removeRegion(this.containerRegion); } }); TabLabels = Marionette.CollectionView.extend({ tagName: "ul" }); TabContainers = Marionette.CollectionView.extend({ tagName: "div" });
视图实例化如下:
tabs = new TabsCollection(); // Create a new collection instance var tabLabelView = new TabLabels({ itemView: TabLabel, collection: tabs }); var tabContainerView = new TabContainers({ itemView: TabContainer, collection: tabs });
如您所见,视图都引用相同的集合; 集合中的每个模型都可以说代表一个标签(恰好是模型包含满足jquery-ui标签的必要信息)。 这些景观通过Marionette在一个地区展出。布局……相当标准。 通过单击选项卡容器中的链接来添加选项卡; 所有这一切都是为集合添加另一个模型,然后在主容器上调用选项卡(“刷新”),这样就会显示新选项卡。 通过单击选项卡右上角的“X”图标可以删除选项卡。
我花了很多时间试图追踪这个泄漏,我无法弄清楚我的代码中是否存在问题(我正在关闭视图/模型等等的方式?)或者是否存在问题jquery-ui tabs插件。
思考? 提前致谢!
更新#1根据要求,这里有一个jsfiddle演示问题 – 只需关闭选项卡,您将看到分离的元素被遗忘。
另外,截图:
更新#2这似乎是jquery-ui tabs小部件中的泄漏。 在jquery-ui网站上的小部件演示中会出现相同的行为。 我添加了几个标签,然后关闭它们,果然,它们仍然存在:
我用最新的(在撰写本文时)版本的jQuery UI(1.10.3)和之前的版本(1.10.2)测试了这个。
你有没有理由使用this.$el.contents().remove()
而不是this.$el.empty()
?
在你的jsFiddle中使用this.$el.empty()
似乎可以解决分离的NodeList。
一些记录内存分析:
- 观看http://www.youtube.com/watch?v=L3ugr9BJqIs
- 使用3快照方法,2是不够的。 那是什么意思?
- 开始新鲜,隐身模式并刷新
- 拍摄快照(每次拍摄快照时都会发生强制GC)
- 做点什么,拍快照(gc)
- 做类似的事情,拍快照(gc)
- 将快照2与快照1进行比较,使用+查找增量
- 选择快照3的快照1和2之间分配的 摘要和对象
- 寻找你发现的比较2和1不应该存在的东西。 这些是韭菜
我发现了jQuery似乎韭菜的情况,因为它们在执行诸如调用.add()
类的操作时会在.prevObject
保存当前的jQuery对象。 也许对.contents()
调用做了一些时髦的魔术。
所以我最终通过做两件事来解决这个问题(很久以前):
- 放弃jQueryUI,转而使用Bootstrap
-
将closeTab函数(请参阅原始jsFiddle)更改为以下内容:
closeTab: function (e) { e.stopPropagation(); e.preventDefault(); this.model.collection.remove(this.model); this.close(); }
在该片段中,stopPropagation和preventDefault实际上是阻止此元素在DOM中保持分离(并在后续添加/删除时累积)的原因。 总结一下:这个问题是通过在触发事件对象后不调用stopPropagation / preventDefault创建的。 我已经更新了jsFiddle,以便正确删除制表符元素,为了后代,这里是结果的屏幕截图:
如您所见,单击“X”关闭它们后,没有任何选项卡元素保持分离状态。 唯一的分离元素是来自jsFiddle接口的元素。