DocumentFragment文档碎片

1,561 阅读4分钟

定义

文档片段接口,一个没有父对象的最小文档对象。

它被作为一个轻量版的 Document 使用,就像标准的document一样,存储由节点(nodes)组成的文档结构。

是 DOM 节点,但不是真实 DOM 树的一部分

与document相比,最大的区别是DocumentFragment 存在于内存中,不是真实 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。

用法

<ul id="list"></ul>
const list = document.querySelector('#list');
const fruits = ['Apple', 'Orange', 'Banana', 'Melon'];

const fragment = document.createDocumentFragment();

fruits.forEach(fruit => {
  const li = document.createElement('li');
  li.innerHTML = fruit;
  fragment.appendChild(li);
});

list.appendChild(fragment);

使用场景

Nod API中使用

使用文档片段作为参数(例如,任何 Node 接口类似 Node.appendChild 和 Node.insertBefore 的方法),这种情况下被添加(append)或被插入(inserted)的是片段的所有子节点, 而非片段本身。

因为所有的节点会被一次插入到文档中,而这个操作仅发生一个重渲染的操作,而不是每个节点分别被插入到文档中,因为后者会发生多次重渲染的操作。

在 Web 组件(Web components)中使用

<template> 元素的 HTMLTemplateElement.content 属性就是一个 DocumentFragment

属性

属性都继承自 Node

继承的 parentNode 属性总是 null。

文档片段节点的三个node属性——nodeTypenodeNamenodeValue分别是11'#document-fragment'null,文档片段节点没有父节点parentNode

let fragement = document.createDocumentFragment()
console.log(fragement.nodeName)//#document-fragment
console.log(fragement.nodeType)//11
console.log(fragement.nodeValue)//null
console.log(fragement.parentNode)//null
// 支持的dom属性
attributes, childNodes, firstChild, lastChild, localName, namespaceURI, nextSibling, nodeName, nodeType, nodeValue, ownerDocument, parentNode, prefix, previousSibling, textContent.
  • ParentNode.children 只读

返回一个实时HTMLCollection,包含所有属于 DocumentFragment 的元素类型的子对象。

  • ParentNode.firstElementChild 只读

返回 DocumentFragment 的第一个 Element 类型的子对象,如果没有则返回 null 。

  • `ParentNode.lastElementChild 只读

返回 DocumentFragment 的最后一个 Element 类型的子对象,如果没有则返回 null 。

  • ParentNode.childElementCount只读

返回一个 unsigned long 给出 DocumentFragment 拥有的子项数量。

方法

继承 Node的全部方法

// 支持的方法
cloneNode, hasAttributes, hasChildNodes, insertBefore, normalize, removeChild, replaceChild.
  • DocumentFragment.querySelector()返回在DocumentFragment中以文档顺序排列的第一个符合指定选择器的Element节点。

  • DocumentFragment.querySelectorAll()返回在DocumentFragment中所有的符合指定选择器的Element节点组成的NodeList数组。

  • DocumentFragment.getElementById()返回在DocumentFragment中以文档顺序排列的第一个符合指定ID选择器的Element节点。与Document.getElementById()作用相同。

兼容性 ie9

image.png

reateElement与createDocumentFragment的区别

参考: juejin.cn/post/698165…

nodeType

  • createElement 创建的是元素节点,节点类型(nodeType)为 1
  • createDocumentFragment 创建的是文档碎片,节点类型(nodeType)为 11

innerHTML

  • createElement 创建的元素可以直接使用 innerHTML 添加子元素。
  • createDocumentFragment 创建的文档碎片不能直接使用 innerHTML 添加子元素,只会变成一个普通属性。
var e1 = document.createElement('div');
e1.innerHTML = '<h1>橙某人</h1>';
document.body.appendChild(e1);
console.log(e1);

var e2 = document.createDocumentFragment();
e2.innerHTML = '<h1>橙某人</h1>';
document.body.appendChild(e2);
console.log(e2);
console.log(e2.innerHTML); // <h1>橙某人</h1>  获取的时候是有的 

页面只会存在 createElement 创建的元素。

image.png

appendChild

  • 使用 appendChildcreateElement 创建的 元素中 追加子元素时,如果将被插入的节点已经存在于当前文档的文档树中,那么 appendChild 只会将它从原先的位置移动到新的位置(不需要事先移除要移动的节点);

如果把createElement 创建的 元素 追加进页面中,则插入的是它本身和它的所有子孙节点;即便它已经添加进了页面,依旧能继续重复操作它。

// html
<body>
    <h1 id="h1">橙某人</h1>
</body>
// js
var e1 = document.createElement('div');
var h1 = document.getElementById('h1');
e1.appendChild(h1); // 页面<h1/>显示会消失
document.body.appendChild(e1); // 整个追加进页面中显示
e1.appendChild(document.createElement('h2')); // 继续重复操作

image.png

  • createDocumentFragment 使用 appendChild 追加子元素时,会把页面中的原来存在的元素删除;如果把它追加进页面中,则插入的不是 DocumentFragment 自身,而是它的所有子孙节点;如果它已经添加进了页面,我们就不能继续操作,它属于一次性操作。
// html
<body>
    <h1 id="h1">橙某人</h1>
</body>
// js
var e2 = document.createDocumentFragment();
var h1 = document.getElementById('h1');
e2.appendChild(h1); // 页面<h1/>显示会消失
document.body.appendChild(e2); // 子孙节点会在页面中显示
e2.appendChild(document.createElement('h2')); // 无效页面不展示

image.png

二者使用 appendChild 追加子元素后返回值都是新添加的子元素。
var e1 = document.createElement('div');
var c1 = e1.appendChild(document.createElement('p'));
console.log(c1); // <p></p>

var e2 = document.createDocumentFragment();
var c2 = e2.appendChild(document.createElement('p'));
console.log(c2); // <p></p>

借助返回值通过 innerHTML 间接给 createDocumentFragment 创建的文档碎片直接添加子元素:
var e2 = document.createDocumentFragment();
var c2 = e2.appendChild(document.createElement('p'))
c2.innerHTML = '<span></span>';
var res = document.body.appendChild(e2);

image.png