JavaScript DocumentFragment
最后修改于 2025 年 4 月 2 日
在本文中,我们将探讨 JavaScript 中的 document.createDocumentFragment 方法。这个强大的工具通过创建轻量级的文档片段,可以在将它们添加到主 DOM 树之前进行修改,从而帮助优化 DOM 操作。
基本定义
DocumentFragment 是一个最小化的文档对象,它没有父节点。它被用作 Document 的轻量级版本,以与标准文档类似的方式存储由节点组成的文档结构片段。
DocumentFragment 的主要优点是,对它的更改在附加到主文档之前不会触发回流或重绘。这使其成为批量 DOM 操作的理想选择。
基本 DocumentFragment 创建
此示例演示了如何创建和使用基本的 DocumentFragment。
<!DOCTYPE html>
<html>
<head>
<title>Basic DocumentFragment</title>
</head>
<body>
<div id="container"></div>
<script>
const fragment = document.createDocumentFragment();
const p1 = document.createElement('p');
p1.textContent = 'First paragraph';
const p2 = document.createElement('p');
p2.textContent = 'Second paragraph';
fragment.appendChild(p1);
fragment.appendChild(p2);
document.getElementById('container').appendChild(fragment);
</script>
</body>
</html>
在此示例中,我们创建一个 DocumentFragment,并向其中添加两个段落元素。然后,将该片段作为一个单一操作附加到容器 div 中。
这种方法比直接将每个段落添加到 DOM 更有效,因为它最大限度地减少了回流。片段充当我们节点的临时容器。
批量 DOM 插入
此示例展示了 DocumentFragment 如何优化元素的批量插入。
<!DOCTYPE html>
<html>
<head>
<title>Batch Insertion</title>
</head>
<body>
<ul id="list"></ul>
<button onclick="addItems()">Add Items</button>
<script>
function addItems() {
const fragment = document.createDocumentFragment();
for (let i = 1; i <= 100; i++) {
const li = document.createElement('li');
li.textContent = `Item ${i}`;
fragment.appendChild(li);
}
document.getElementById('list').appendChild(fragment);
}
</script>
</body>
</html>
在这里,我们创建 100 个列表项,并将它们添加到 DocumentFragment 中,然后再一次性将它们插入到 DOM 中。这比单独添加每个列表项要有效得多。
没有 DocumentFragment,浏览器会在每次插入后回流。使用它,我们在片段附加到实际 DOM 时只发生一次回流。
模板克隆
此示例演示了将 DocumentFragment 与模板元素一起使用。
<!DOCTYPE html>
<html>
<head>
<title>Template Cloning</title>
</head>
<body>
<template id="productTemplate">
<div class="product">
<h3></h3>
<p class="price"></p>
</div>
</template>
<div id="products"></div>
<button onclick="addProducts()">Add Products</button>
<script>
function addProducts() {
const template = document.getElementById('productTemplate');
const fragment = document.createDocumentFragment();
const products = [
{ name: 'Laptop', price: '$999' },
{ name: 'Phone', price: '$699' },
{ name: 'Tablet', price: '$399' }
];
products.forEach(product => {
const instance = template.content.cloneNode(true);
instance.querySelector('h3').textContent = product.name;
instance.querySelector('.price').textContent = product.price;
fragment.appendChild(instance);
});
document.getElementById('products').appendChild(fragment);
}
</script>
</body>
</html>
此示例结合了 HTML 模板和 DocumentFragment,以实现高效的 DOM 创建。我们将每个产品的模板内容克隆一份,并在插入之前将其添加到片段中。
模板内容本身就是一个 DocumentFragment,我们会克隆并修改它,然后再添加到我们的主片段中。这种模式对于重复的 UI 元素非常有效。
移动现有节点
此示例展示了如何使用 DocumentFragment 来移动现有的 DOM 节点。
<!DOCTYPE html>
<html>
<head>
<title>Moving Nodes</title>
</head>
<body>
<div id="source">
<p>First paragraph</p>
<p>Second paragraph</p>
<p>Third paragraph</p>
</div>
<div id="destination"></div>
<button onclick="moveNodes()">Move Paragraphs</button>
<script>
function moveNodes() {
const source = document.getElementById('source');
const fragment = document.createDocumentFragment();
while (source.firstChild) {
fragment.appendChild(source.firstChild);
}
document.getElementById('destination').appendChild(fragment);
}
</script>
</body>
</html>
在这里,我们使用 DocumentFragment 将源 div 的所有子节点移动到目标 div。这比逐个移动节点更有效。
在移动操作过程中,片段会临时保存节点。这项技术在不使用临时变量的情况下重组 DOM 结构时非常有用。
性能比较
此示例演示了使用 DocumentFragment 与直接 DOM 操作之间的性能差异。
<!DOCTYPE html>
<html>
<head>
<title>Performance Comparison</title>
</head>
<body>
<button onclick="testFragment()">Test Fragment</button>
<button onclick="testDirect()">Test Direct</button>
<div id="results"></div>
<script>
function testFragment() {
const start = performance.now();
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
fragment.appendChild(div);
}
document.body.appendChild(fragment);
const time = performance.now() - start;
document.getElementById('results').textContent =
`Fragment time: ${time.toFixed(2)}ms`;
}
function testDirect() {
const start = performance.now();
for (let i = 0; i < 1000; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
document.body.appendChild(div);
}
const time = performance.now() - start;
document.getElementById('results').textContent =
`Direct time: ${time.toFixed(2)}ms`;
}
</script>
</body>
</html>
此示例比较了使用 DocumentFragment 添加 1000 个元素与直接将它们添加到 DOM 的性能。片段方法要快得多。
性能差异源于减少的回流。每次直接追加都会导致一次回流,而片段方法最终只产生一次回流。
来源
在本文中,我们展示了如何在 JavaScript 中使用 document.createDocumentFragment。这项技术对于优化 DOM 操作和提高 Web 应用程序性能至关重要。
作者
列出 所有 JS DOM 教程。