You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在原生JavaScript中使用类似createElement的函数而非innerHTML/insertAdjacentHTML的原因

在原生JavaScript中使用类似createElement的函数而非innerHTML/insertAdjacentHTML的原因

嘿,这个问题问得特别实在——我当初从React转写原生JS项目的时候,也纠结过好一阵子:明明用innerHTML加模板字符串写起来更短,为啥还要费劲写createElement那一套?后来在踩了不少坑之后,才明白这俩方案的适用场景差挺多的,下面就给你唠唠用createElement风格方案的核心优势:

1. 安全性:从根源避免XSS攻击

这绝对是最关键的一点!如果你的代码里要插入用户输入的内容(比如评论、用户名、搜索关键词),用innerHTML/insertAdjacentHTML简直是给自己埋雷。因为这两个方法会把传入的字符串直接当作HTML解析执行,如果用户输入了恶意代码(比如<img src=x onerror="stealCookies()">这种),浏览器会老老实实执行里面的脚本,分分钟遭遇XSS攻击。

举个直观的对比:

  • 危险的innerHTML写法:
    const userInput = '<img src=x onerror="alert(\'你的页面被攻陷了!\')">';
    document.body.innerHTML = userInput; // 直接触发弹窗!
    
  • 安全的createElement写法:
    const userInput = '<img src=x onerror="alert(\'你的页面被攻陷了!\')">';
    const container = document.createElement('div');
    container.textContent = userInput; // 只会把内容当作纯文本显示,不会执行任何代码
    document.body.appendChild(container);
    
    用textContent(或者createTextNode)会自动转义所有HTML特殊字符,恶意代码只会变成普通文本,根本没机会作妖。

2. 更精准的DOM元素操控

用createElement创建元素时,你直接拿到的是真实的DOM节点引用,可以立刻给它绑定事件、修改属性、调整样式,后续要再操作这个元素也不用再去页面里查询。

比如:

const toggleBtn = document.createElement('button');
toggleBtn.textContent = '切换主题';
toggleBtn.classList.add('theme-btn');
// 直接绑定事件,不用后续查询
toggleBtn.addEventListener('click', () => {
  document.body.classList.toggle('dark-theme');
});
// 还能随时修改属性
toggleBtn.disabled = false;
document.body.appendChild(toggleBtn);

要是用innerHTML的话,你得先把HTML插进去,再用querySelector去捞这个按钮——不仅多了一步,还容易因为页面结构变动捞错元素,或者压根捞不到,特别闹心。

3. 性能优化:减少不必要的重绘重排

当你需要批量创建元素时,createElement配合DocumentFragment可以把重绘重排的次数降到最低。比如要创建1000个列表项:

const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
  const li = document.createElement('li');
  li.textContent = `列表项 ${i + 1}`;
  fragment.appendChild(li);
}
// 只把fragment插入一次,触发一次重排
document.querySelector('.list-container').appendChild(fragment);

而用innerHTML的话,你要么循环拼接字符串(数据量大的时候字符串拼接本身就有性能开销),要么一次性插入,但innerHTML会先销毁目标节点下的所有子元素再重建,要是你只是追加元素而非替换,这就属于完全没必要的额外开销了。

4. 大型项目的可维护性更强

在规模大一点的项目里,用createElement(或者自己封装的DOM创建函数)能让代码更模块化、更易复用。比如你可以封装一个通用的按钮创建函数:

function createPrimaryButton(text, onClick) {
  const button = document.createElement('button');
  button.textContent = text;
  button.classList.add('primary-btn', 'rounded');
  button.addEventListener('click', onClick);
  return button;
}

之后每次需要按钮的时候,直接调用createPrimaryButton('提交', handleSubmit)就行,不用重复写一堆HTML字符串,也不会因为字符串拼接时的引号不匹配、标签没闭合这种小错误浪费时间排查。

而用innerHTML的话,HTML字符串越长,越容易藏着这种低级错误,而且修改起来也麻烦——要改个样式,得在字符串里找对应的class;要加个事件,还得先插入再查元素,完全不如直接操作DOM节点顺手。

5. 避免意外的副作用

用innerHTML插入HTML的时候,浏览器会解析里面的所有内容,包括<style>、<script>甚至是自定义属性,很可能会意外影响页面已有的样式或行为。比如你插入的HTML里带了个<style>body { background: red !important; }</style>,整个页面的背景色就全变了,这种意外在大型项目里排查起来特别头疼。

而createElement创建的元素是“干净”的,你给它加什么属性、样式、事件,完全在你的控制范围内,不会出现这种莫名其妙的副作用。

备注:内容来源于stack exchange,提问作者mohammad ghohestani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 14:08:03