如何将HTML字符转换为DOM节点并动态添加到文档中详解
作者:玄魂工作室 发布时间:2023-08-23 12:26:39
前言
将字符串动态转换为DOM节点,在开发中经常遇到,尤其在模板引擎中更是不可或缺的技术。
字符串转换为DOM节点本身并不难,本篇文章主要涉及两个主题:
1 字符串转换为HTML DOM节点的基本方法及性能测试
2 动态生成的DOM节点添加到文档中的方法及性能测试
本文的示例: 有如下代码段
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id='container'>
<!-- 动态添加div
<div class='child'> XXX</div>
-->
</div>
</body>
</html>
任务是编写一个JavaScript函数,接收一个文本内容,动态生成一个包含该文本的div,返回该Node。下面话不多说了,来随着小编一起看看详细的介绍吧。
1.1 动态创建Node
1.1.1 innerHTML
第一种方法,我们使用document.createElement
方法创建新的元素,然后利用innerHTML将字符串注入进去,最后返回firstChild,得到动态创建的Node。
<script>
function createNode(txt) {
const template = `<div class='child'>${txt}</div>`;
let tempNode = document.createElement('div');
tempNode.innerHTML = template;
return tempNode.firstChild;
}
const container = document.getElementById('container');
container.appendChild(createNode('hello'));
</script>
下面我们看第二种方法
1.1.2 DOMParser
DOMParser 实例的parseFromString方法可以用来直接将字符串转换为document 文档对象。有了document之后,我们就可以利用各种DOM Api来进行操作了。
function createDocument(txt) {
const template = `<div class='child'>${txt}</div>`;
let doc = new DOMParser().parseFromString(template, 'text/html');
let div = doc.querySelector('.child');
return div;
}
const container = document.getElementById('container');
container.appendChild(createDocument('hello'));
1.1.2 DocumentFragment
DocumentFragment 对象表示一个没有父级文件的最小文档对象。它被当做一个轻量版的 Document 使用,用于存储已排好版的或尚未打理好格式的XML片段。最大的区别是因为DocumentFragment不是真实DOM树的一部分,它的变化不会引起DOM树的重新渲染的操作(reflow) ,且不会导致性能等问题。
利用document.createRange().createContextualFragment
方法,我们可以直接将字符串转化为DocumentFragment对象。
function createDocumentFragment(txt) {
const template = `<div class='child'>${txt}</div>`;
let frag = document.createRange().createContextualFragment(template);
return frag;
}
const container = document.getElementById('container');
container.appendChild(createDocumentFragment('hello'));
这里要注意的是我们直接将生成的DocumentFragment对象插入到目标节点中,这会将其所有自己点插入到目标节点中,不包含自身。我们也可以使用
frag.firstChild
来获取生成的div。
1.1.3 性能测试
下面我们来简单比对下上面三种方法的性能,只是测试生成单个节点,在实际使用中并不一定有实际意义。
先测试createNode。
function createNode(txt) {
const template = `<div class='child'>${txt}</div>`;
let start = Date.now();
for (let i = 0; i < 1000000; i++) {
let tempNode = document.createElement('div');
tempNode.innerHTML = template;
let node = tempNode.firstChild;
}
console.log(Date.now() - start);
}
createNode('hello');
测试100万个Node生成,用时 6322。
再来测试createDocument。
function createDocument(txt) {
const template = `<div class='child'>${txt}</div>`;
let start = Date.now();
for (let i = 0; i < 1000000; i++) {
let doc = new DOMParser().parseFromString(template, 'text/html');
let div = doc.firstChild;
}
console.log(Date.now() - start);
}
createDocument('hello');
测试100万个Node生成,用时 55188。
最后来测试createDocumentFragment.
function createDocumentFragment(txt) {
const template = `<div class='child'>${txt}</div>`;
let start = Date.now();
for (let i = 0; i < 1000000; i++) {
let frag = document.createRange().createContextualFragment(template);
}
console.log(Date.now() - start);
}
createDocumentFragment();
测试100万个Node生成,用时 6210。
createDocumentFragment方法和createNode方法,在这轮测试中不相上下。下面我们看看将生成的DOM元素动态添加到文档中的方法。
1.2.0 批量添加节点
被动态创建出来的节点大多数情况都是要添加到文档中,显示出来的。下面我们来介绍并对比几种常用的方案。
下面我们批量添加的方法都采用createDocumentFragment方法。
1.2.1 直接append
直接append方法,就是生成一个节点就添加到文档中,当然这会引起布局变化,被普遍认为是性能最差的方法。
const template = "<div class='child'>hello</div>";
function createDocumentFragment() {
let frag = document.createRange().createContextualFragment(template);
return frag;
}
// createDocumentFragment();
const container = document.getElementById('container');
let start = Date.now();
for (let i = 0; i < 100000; i++) {
container.appendChild(createDocumentFragment());
}
console.log(Date.now() - start);
上面的代码我们测算动态添加10万个节点。结果如下:
测试1000个节点耗时20毫秒,测试10000个节点耗时10001毫秒,测试100000个节点耗时46549毫秒。
1.2.2 DocumentFragment
上面我们已经介绍过DocumentFragment了,利用它转换字符串。下面我们利用该对象来作为临时容器,一次性添加多个节点。
利用document.createDocumentFragment()
方法可以创建一个空的DocumentFragment对象。
const template = "<div class='child'>hello</div>";
function createDocumentFragment() {
let frag = document.createRange().createContextualFragment(template);
return frag;
}
// createDocumentFragment();
const container = document.getElementById('container');
let fragContainer = document.createDocumentFragment();
let start = Date.now();
for (let i = 0; i < 1000; i++) {
fragContainer.appendChild(createDocumentFragment());
}
container.appendChild(fragContainer);
console.log(Date.now() - start);
测试1000个节点耗时25毫秒,10000个节点耗时2877毫秒,100000个节点浏览器卡死。
1.3 小结
简单了介绍了几种方法,并没有什么技术含量。但是从动态添加节点来看,网上说的DocumentFragment方法性能远远好于直接append的说法在我的测试场景中并不成立。
DocumentFragment正确的应用场景应该是作为虚拟DOM容器,在频繁修改查询但是并不需要直接渲染的场景中。
来源:https://www.cnblogs.com/xuanhun/p/9499348.html


猜你喜欢
- python-opencv 中值滤波{cv2.medianBlur(src, ksize)}中值滤波将图像的每个像素用邻域 (以当前像素为中
- Null模式我想每个人都有一种经历,为了获取某属性,但是有时候属性是None,那么需要你做异常处理, 而假如你想节省这样的条件过滤的代码,可
- 环境配置新建python虚拟环境并激活conda create -n pyqt python=3.8conda activate py36安
- 前言tips:第一次发技术文章,篇幅比较简短,主要采取文字和关键代码表现的形式,希望帮助到大家。(若有不正确还请多多指正)nextTick作
- 今天好不容易闲下来半天,所以和大家分享一下我之前总结的一套Web UI 设计命名规范,也就是网站用户界面设计(俗称网页设计)命名规范。这套规
- 泛型,如果你学过Java ,应该对它不陌生吧。但你可能不知道在 Python 中(3.4+ ),也可以实现简单的泛型函数。在Python中只
- 决策树分类与上一篇博客k近邻分类的最大的区别就在于,k近邻是没有训练过程的,而决策树是通过对训练数据进行分析,从而构造决策树,通过决策树来对
- 本文实例讲述了C#操作SQLite数据库之读写数据库的方法。分享给大家供大家参考,具体如下:这里演示读写数据库并在窗体(Form)中显示其数
- 本文实例讲述了sql server实现在多个数据库间快速查询某个表信息的方法。分享给大家供大家参考,具体如下:最近出来实习,所在公司的服务器
- 前一段时间完成了一个数据可视化项目,由后台NodeJS+Highcharts框架进行搭建。下面分享一下整个开发过程的流程,以及使用Highc
- GitHub : https://github.com/jayknoxqu/id-number-util身份组成方式中华人民共和国国家标准G
- Go语言中有缓冲的通道(buffered channel)是一种在被接收前能存储一个或者多个值的通道。这种类型的通道并不强制要求 gorou
- 安装前的准备1.python的安装和配置在Window下:在开始菜单中找到运行输入cmd或直接搜索cmd点击进入,输入python,如果出现
- 1. 错误描述之前在学习Python的过程中,导入自己写的包文件时,与之相关的方法等都会被划红线,但并不影响代码执行,如图:看着红线确实有点
- 网络爬虫网络爬虫是指在互联网上自动爬取网站内容信息的程序,也被称作网络蜘蛛或网络机器人。大型的爬虫程序被广泛应用于搜索引擎、数据挖掘等领域,
- 前言在python中, 切片是一个经常会使用到的语法, 不管是元组, 列表还是字符串, 一般语法就是:sequence[ilow:ihigh
- 前面已经提到,CSS之所以如此强大,是因为它采用HTML文档结构来决定其样式的应用。但这仅仅只是一方面,因为它只暗示了CSS之所以使用文档结
- 一、关闭数据库[oracle@RHEL5]$sqlplus / as sysdba SQL>shutdown immediate; 二
- 内容摘要:本文是一篇实例讲解的文章。作为一个普通的程序员,我深知,一个优秀的例程,对于正在学习编程的人是多么的有帮助。本文中使用的例程,是一
- 前言:[学习SQL SERVER 2005系列]准备把学习2005的一些心得整理出来,和大家分享,共同学习一起提高。sql2005 精简版下