删除 div 中的所有子 DOM 元素。

133

我有以下的Dojo代码来在一个div下创建一个surface图形元素:

....
<script type=text/javascript>
....
   function drawRec(){
      var node = dojo.byId("surface");
      //   remove all the children graphics
      var surface = dojox.gfx.createSurface(node, 600, 600);

      surface.createLine({
         x1 : 0,
         y1 : 0,
         x2 : 600,
         y2 : 600
      }).setStroke("black");
   }
....
</script>
....
<body>
<div id="surface"></div>
....

drawRec()会在第一次调用时绘制一个矩形图形。如果我像这样在锚链接中再次调用此函数:

 <a href="javascript:drawRec();">...</a>

它将再次绘制另一个图形。 我需要清除div下所有的图形,然后再创建。我该如何添加一些dojo代码来实现?

8个回答

292
while (node.hasChildNodes()) {
    node.removeChild(node.lastChild);
}

17
仅仅是为了严谨起见 --- 删除没有相应 JS 对象的 DOM 节点会导致内存泄漏。 - Eugene Lazutkin
2
@Eugene:你能多说一些吗? - Tom Anderson
7
@Tom:dojox.gfx创建JavaScript对象以与底层图形系统通信,该系统可能具有DOM节点(SVG、VML)或没有(Silverlight、Flash、Canvas)。从DOM中删除DOM节点不会删除那些JavaScript对象,也不会删除DOM节点,因为JavaScript对象仍然引用这些DOM节点。处理此情况的正确方法已在我对此问题的答案中描述。 - Eugene Lazutkin
3
@robocat,这与IE无关:JS对象引用DOM对象并将其保留在内存中,底层JS对象通过其他JS对象的引用保留在内存中。例如:一个gfx表面引用所有子元素,一个组也引用所有子元素,依此类推。仅删除DOM节点是不够的。 - Eugene Lazutkin
3
@david-chu-ca - 可能应该将Eugene(道场GFX库的主要作者之一)的后来的回答标记为被接受的答案。Eugene-感谢您的澄清。 - robocat
显示剩余7条评论

48
node.innerHTML = "";

虽然不是标准做法,但速度快且支持良好。


2
不支持IE。请查看:http://www.theogray.com/blog/2009/06/internet-explorer-unknown-runtime-error - Rajat
4
似乎在HTML 5中是标准的。上面的博客文章是用户错误。https://developer.mozilla.org/en-US/docs/DOM/element.innerHTML - svachalek
根据用户stwissel的说法,innerHTML只适用于处理HTML。如果内部包含SVG等内容,则仅元素删除才有效。 - robocat
6
相对于删除节点而言,执行速度会更慢:http://jsperf.com/innerhtml-vs-removechild/15 - robocat
除了其他评论中描述的一些可能的缺点之外,这对于大多数情况来说都是一个不错的解决方案。 - gitaarik
显示剩余3条评论

24
首先,您需要创建一个表面,并将其放在方便的位置。例如:
var surface = dojox.gfx.createSurface(domNode, widthInPx, heightInPx);

domNode一般是一个未被修饰的<div>,用作表面的占位符。

您可以一次性清除表面上的所有内容(所有现有的形状对象都将失效,在此之后不要再使用它们):

surface.clear();

所有与 Surface 相关的函数和方法都可以在官方文档 dojox.gfx.Surface 中找到。使用示例可以在 dojox / gfx / tests / 中找到。


请问您能否添加如何创建表面的说明?对于像我这样的用户可能不太清楚。谢谢。 - Luca Borrione

20
while(node.firstChild) {
    node.removeChild(node.firstChild);
}

1
jQuery 1.x 的 empty() 是这样工作的。在只支持现代浏览器的 jQuery 2.x 中,empty() 使用 elem.textContent = ""; 然而 只是因为 jQuery 这样做并不意味着它没有缺陷,例如 stwissel 表示 "innerHTML 只适用于处理 HTML。如果里面有 SVG 等,则仅元素删除将起作用"。此外,请参见其他相关说明:https://dev59.com/eG865IYBdhLWcg3wKLT6 - robocat

18

在Dojo 1.7或更新版本中,请使用domConstruct.empty(String|DomNode)

require(["dojo/dom-construct"], function(domConstruct){
  // Empty node's children byId:
  domConstruct.empty("someId");
});

在旧版本的Dojo中,请使用dojo.empty(String|DomNode)(已弃用于Dojo 1.8):

dojo.empty( id or DOM node );

这些empty方法会安全地删除节点的所有子节点。


3

根据 Dojo API 文档

dojo.html._emptyNode(node);

2
如果你正在寻找一种现代化的>1.7 Dojo方式来销毁所有节点的子元素,那么这就是方法:
// Destroys all domNode's children nodes
// domNode can be a node or its id:
domConstruct.empty(domNode);

安全地清空DOM元素的内容。empty()删除所有子元素,但保留节点。 查看“dom-construct”文档以获取更多详细信息。
// Destroys domNode and all it's children
domConstruct.destroy(domNode);

销毁一个DOM元素。destroy()会删除所有子元素和该节点本身。

1
他只想要移除子元素,这意味着在这种情况下使用 domConstruct.empty() 会更好。 - g00glen00b

0
const wipeOut = elm => [...elm.childNodes].forEach(child => child.remove());

wipeOut(elm);

@SebastianSimon 是的,你说得对。我更新了我的答案,并意识到我需要将节点列表转换为数组,以便清除传递的父级的所有子项,尽管 foreach 方法可以使用节点列表! - Eissa Saber
1
是的,原因在querySelectorAll和getElementsBy*方法返回什么?中提到。.childNodes是一个动态节点列表,因此在循环中删除这些节点会干扰循环。 - Sebastian Simon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接