为什么需要 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 中某些属性只要存在就生效(比如 disabled、checked、readonly),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 能帮你处理得更智能
一个好的转换器应该能自动处理:
class→classNamestyle字符串 → 对象for→htmlFor- 自闭合标签补全
- 属性名驼峰化
- 事件名转换
小结
HTML 转 JSX 看似简单,但细节不少。记住几个核心原则就能避免大部分坑:
- 属性名用驼峰——
className、htmlFor、onClick等 - style 是对象——不是字符串
- 标签必须闭合——没有子元素就用自闭合
- JS 表达式用
{}——代替 HTML 中的字符串插值
掌握这些规则,再配合合适的工具,HTML 转 JSX 就不再是麻烦事了。