Skip to content
code2026-07-264 分钟阅读

为什么需要 HTML 转 JSX

在 React 开发中,我们经常需要将现成的 HTML 代码嵌入到组件中。可能是从设计稿导出的 HTML 结构,可能是从其他项目复制的页面片段,也可能是从 UI 组件库文档里拿到的示例代码。

直接把 HTML 粘进 React 组件里,十有八九会报错。最常见的就是:

不想手动改?用我们的 HTML 转 JSX 工具className、驼峰属性、自闭合标签全自动处理。

Warning: Invalid DOM property `class`. Did you mean `className`?

这是因为 JSX 虽然长得像 HTML,但本质上是 JavaScript 的语法扩展,有自己的一套规则。HTML 属性名和 JSX 属性名并不完全一致。

HTML 与 JSX 的核心差异

1. class → className

这是最广为人知的区别。因为 class 是 JavaScript 的保留字,所以在 JSX 中要用 className 代替:

<!-- HTML -->
<div class="container card shadow">
  <p class="text-sm text-gray-600">Hello</p>
</div>
{/* JSX */}
<div className="container card shadow">
  <p className="text-sm text-gray-600">Hello</p>
</div>

2. style 属性从字符串变成对象

HTML 中 style 是一个字符串,JSX 中 style 必须是一个对象,而且属性名要用驼峰式:

<!-- HTML -->
<div style="margin-top: 20px; background-color: #f0f0f0; font-size: 14px;">
  content
</div>
{/* JSX */}
<div style={{ marginTop: '20px', backgroundColor: '#f0f0f0', fontSize: '14px' }}>
  content
</div>

注意外层的双花括号 {{ }}——外层是 JSX 表达式语法,内层才是对象字面量。

3. for → htmlFor

<label> 标签的 for 属性也要改名,原因和 class 一样:

<!-- HTML -->
<label for="email">Email</label>
<input id="email" type="email">
{/* JSX */}
<label htmlFor="email">Email</label>
<input id="email" type="email" />

4. 自闭合标签

HTML 中很多标签可以不写闭合标签(比如 <br><img><input>),但 JSX 要求所有标签都必须闭合。没有子元素的标签要用自闭合形式:

<!-- HTML -->
<img src="logo.png" alt="logo">
<br>
<input type="text" placeholder="Enter name">
<meta charset="utf-8">
{/* JSX */}
<img src="logo.png" alt="logo" />
<br />
<input type="text" placeholder="Enter name" />
<meta charSet="utf-8" />

顺便一提,charset 也要写成 charSet

5. 事件处理函数

HTML 中事件属性是全小写的,值是字符串形式的代码:

<button onclick="handleClick()">点击我</button>

JSX 中事件名用驼峰式,值是函数引用:

<button onClick={handleClick}>点击我</button>

常见的对应关系:

| HTML 属性 | JSX 属性 | |-----------|----------| | onclick | onClick | | onchange | onChange | | onsubmit | onSubmit | | onkeydown | onKeyDown | | onmouseover | onMouseOver | | onfocus | onFocus | | onblur | onBlur |

6. 其他属性名差异

还有一些属性名在 JSX 中使用了不同的命名:

| HTML 属性 | JSX 属性 | 说明 | |-----------|----------|------| | tabindex | tabIndex | 驼峰式 | | readonly | readOnly | 驼峰式 | | maxlength | maxLength | 驼峰式 | | cellspacing | cellSpacing | 驼峰式 | | cellpadding | cellPadding | 驼峰式 | | colspan | colSpan | 驼峰式 | | rowspan | rowSpan | 驼峰式 | | usemap | useMap | 驼峰式 | | contenteditable | contentEditable | 驼峰式 | | crossorigin | crossOrigin | 驼峰式 | | datetime | dateTime | 驼峰式(time 标签) | | autocomplete | autoComplete | 驼峰式 | | autofocus | autoFocus | 驼峰式 | | autoplay | autoPlay | 驼峰式 |

基本上所有由多个单词组成的 HTML 属性,在 JSX 中都要改成驼峰命名法。

常见转换陷阱

注释写法不同

<!-- HTML 注释 -->
{/* JSX 注释 */}

内联事件中的 this

HTML 中 onclick="foo()" 调用的是全局函数,JSX 中要注意 this 绑定问题,通常用箭头函数或者 bind 来处理。

布尔属性

HTML 中某些属性只要存在就生效(比如 disabledcheckedreadonly),JSX 中需要显式传递布尔值:

<!-- HTML -->
<input disabled>
<input checked>
{/* JSX */}
<input disabled={true} />
<input checked={true} />
{/* 或者更简洁地 */}
<input disabled />
<input checked />

dangerouslySetInnerHTML

如果确实需要直接设置 HTML 内容(比如渲染富文本),不能直接用 innerHTML,必须用 dangerouslySetInnerHTML

<div dangerouslySetInnerHTML={{ __html: '<p>原始 HTML 内容</p>' }} />

React 特意把这个 API 设计得很"丑陋",就是为了提醒你:直接注入 HTML 有 XSS 风险,要谨慎使用。

工具推荐

手动转换 HTML 到 JSX 既枯燥又容易出错。对于复杂的 HTML 片段,建议使用自动化工具:

  • HTML to JSX 在线转换器:直接粘贴 HTML,一键转换为符合规范的 JSX 代码
  • VS Code 插件:有些插件可以在编辑器内完成转换
  • ChatGPT / Claude 等 AI 工具:对于特别复杂的结构,AI 能帮你处理得更智能

一个好的转换器应该能自动处理:

  • classclassName
  • style 字符串 → 对象
  • forhtmlFor
  • 自闭合标签补全
  • 属性名驼峰化
  • 事件名转换

小结

HTML 转 JSX 看似简单,但细节不少。记住几个核心原则就能避免大部分坑:

  1. 属性名用驼峰——classNamehtmlForonClick
  2. style 是对象——不是字符串
  3. 标签必须闭合——没有子元素就用自闭合
  4. JS 表达式用 {}——代替 HTML 中的字符串插值

掌握这些规则,再配合合适的工具,HTML 转 JSX 就不再是麻烦事了。


广告