删除DOM元素上0(1)中的所有childNodes

时间:2019-03-05 18:16:28

标签: javascript html dom

当查看父节点的子节点时,数据结构似乎是一个像对象的数组。

代替遍历每个childNode并删除它-是否可以仅删除类似数组的对象?

我在这里考虑表演,并希望避免遍历孩子并一一删除。

就我而言,我正在父级Ul上创建子级Li元素:

  _createLi(address) {
    const parentUl = document.querySelector("ul#parent");
    const li = document.createElement("li");
    li.appendChild(document.createTextNode(address));
    parentUl.appendChild(li);
  }

我可以这样删除它们:

  _removeLi(node) {
    while (!node.lastChild) node.removeChild(!node.lastChild);
  }

这有效,但是遍历每个节点。 您如何通过删除包含子节点的数组之类的对象来删除所有子节点,并且在O(1)中是否可能?

2 个答案:

答案 0 :(得分:2)

我真的怀疑即使在使用node.innerHTML = ''的情况下也可以在O(1)中删除子级,因为基础实现很可能是O(N)操作。

您应该考虑提高性能的是,尽量减少DOM回流的次数。

  1. 您可以尝试用克隆替换元素。

const list = document.querySelector('ul');
const listClone = list.cloneNode(false);
list.parentNode.replaceChild(listClone, list);
<ul>
  <li>First</li>
  <li>Last</li>
</ul>

  1. 您可以尝试从DOM中删除列表,执行操作并将其重新添加。

withElOutOfFlow(document.querySelector('ul'), el => {
   while(el.lastChild) el.removeChild(el.lastChild);
});

function withElOutOfFlow(el, callback) {
  const parent = el.parentNode;
  
  if (!parent) {
    callback(e);
    return;
  }
  
  const nextSibling = el.nextSibling;
  parent.removeChild(el);
  callback(el);
  
  if (nextSibling) parent.insertBefore(el, nextSibling);
  else parent.appendChild(el);
}
<ul>
  <li>First</li>
  <li>Last</li>
<ul>

答案 1 :(得分:2)

更新

Faster than .cloneNode() and .replaceChild()

Range API

5% faster than ALL examples
(包括接受的答案)

以下示例来自 Range API

const rng = document.createRange();
rng.selectNodeContents(document.querySelector('ul'));
rng.deleteContents();

范围界面处理由节点和文本组成的文档片段。尽管它显示的时间很慢,但it's actually fast100% compatible with all browsers

范围方法

  

.createRange()
  .selectNodeContents()
  .deleteContents()


.replaceWith().createElement()

15% slower than All examples
此组合比大多数示例都快,且冗长(除了 Range 演示最快)。

 document.querySelector('ul').replaceWith(document.createElement('ul'));

这是2个DOM交互:查找列表并将其替换为空列表。请参阅演示1。If you want to support IE11 (ATM 2.26% global share),然后不要使用它。


演示1

范围API

const rng = document.createRange();
rng.selectNodeContents(document.querySelector('ul'));
rng.deleteContents();
ul {
  min-height: 30px;
  min-width: 30px;
  outline: 1px dashed red;
}
<ul>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
</ul>


演示2

.replaceWith().createElement()

document.querySelector('ul').replaceWith(document.createElement('ul'));
ul {
  min-height: 30px;
  min-width: 30px;
  outline: 1px dashed red;
}
<ul>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
</ul>


.insertAdjacentHTML().createDocumentFragment()

比所有示例慢50%
优化任何DOM操作的最佳方法是不要使用它们。将DOM访问限制到最低限度–这非常耗时。每次JS引擎寻找元素时,它将遍历DOM树,每次添加或删除标签时,都必须重新计算DOM中已经存在的节点(元素,文本等)的位置和尺寸,因此即使如果所涉及的节点数很少,那么对于浏览器来说,这可能会花费很多时间。这称为重排,涉及CSS样式的类似问题称为重绘。


以下演示通过4个DOM操作删除了<li>中的所有<ul>

  
      
  1. 引用<ul>-1查找

  2.   
  3. <ul>的引用父项附加一个空的<ul>-1个查询,1个添加项

  4.   
  5. 创建一个documentFragment并将原始<ul>附加到其中-删除1次

  6.   

.insertAdjacentHTML()无损地将htmlString渲染为HTML和it's highly optimized

.createDocumentFragment() never touches the DOM,附加的内容不再与DOM接触。


演示3

.insertAdjacentHTML.createDocumentFragment()

// Reference the <ul>
const list = document.querySelector('ul');

// Reference parent of <ul> append an empty <ul>
list.parentElement.insertAdjacentHTML('beforeend', `<ul></ul>`);

// Create a document fragment and append original <ul> to it
document.createDocumentFragment().appendChild(list);
ul {
  min-height: 30px;
  min-width: 30px;
  outline: 1px dashed red;
}
<ul>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
</ul>