HTML 转 JSX 完全指南:class、style、自闭合那些坑
把现成 HTML 改成 React 组件时,class 转 className、for 转 htmlFor、内联样式转对象、属性驼峰化全是坑。这篇讲清规则,附一段真实的转换前后例子。
HTML 转 JSX 完全指南:class、style、自闭合那些坑
接手一份手写的静态页,想把它做成 React 组件,直接把 HTML 粘进 .jsx 文件,大概率第一行 class= 就编译报错。JSX 看起来像 HTML,但它不是 HTML,它最终会编译成 JavaScript。这篇把几个最常踩的差异点讲清楚,顺便给你一条不用手工查找替换的路。
为什么 JSX 不收原始 HTML
JSX 里的标签语法只是 React.createElement 调用的语法糖。既然要编译成 JavaScript,那些在 JavaScript 里有特殊含义的词就不能直接用作属性名。class 是类声明的保留字,for 是循环的保留字。React 于是改用 DOM IDL 属性名:class 写成 className(对应 element.className),for 写成 htmlFor(对应 label.htmlFor)。这不是 React 故意为难你,是 JavaScript 语言层面的约束。
同样的道理,很多属性要写成驼峰:tabindex 转 tabIndex,maxlength 转 maxLength,readonly 转 readOnly,srcset 转 srcSet,所有 on* 事件也驼峰化,onclick 变 onClick。这些在你不转的时候,React 会用一堆警告反复唠叨。
class 转 className、for 转 htmlFor
这是出现频率最高的两个。一段普通的表单:
<label class="field" for="email">邮箱</label>
<input id="email" class="input" type="email" />
转成 JSX 后:
<label className="field" htmlFor="email">邮箱</label>
<input id="email" className="input" type="email" />
注意 id、type 这些原样保留,只有 React 专属的那套才改名。一个反直觉的点:aria-* 和 data-* 属性不驼峰化。React 把它们的连字符写法原样透传,aria-label 还是 aria-label,data-toggle 还是 data-toggle。你要是手贱把它们也驼峰了,属性反而写坏。
内联样式:从字符串到对象
HTML 里 style 是一个字符串,JSX 里 style 接的是一个 JavaScript 对象。React 通过 element.style API 应用样式,这个 API 的键是驼峰式属性名。所以一段:
<div style="color:red;margin-top:8px;background-color:#f5f5f5">提示</div>
要变成:
<div style={{ color: 'red', marginTop: '8px', backgroundColor: '#f5f5f5' }}>提示</div>
按分号拆开,每个属性驼峰化,background-color 变 backgroundColor,再包成对象字面量。--brand 这类 CSS 自定义属性是个例外,要原样保留,因为 React 会原封不动透传它们。
自闭合、注释、布尔属性
HTML 里 <br>、<img src="...">、<input> 可以不闭合,JSX 里这些 void 元素必须自闭合,写成 <br />、<img src="..." />。空元素同理。
注释也变了。HTML 的 <!-- 注释 --> 在 JSX 里不合法,要写成 {/* 注释 */}。整页粘进来的话,<!DOCTYPE> 直接丢掉。
布尔属性是另一个坑。HTML 里 <input disabled> 是有或没有,JSX 要一个明确的值,写成 disabled={true}。有值的属性保留字符串,value="5" 不动。
一段真实的转换前后
下面这段 HTML 几乎把上面所有坑都占了:
<!-- 登录卡片 -->
<div class="card" style="padding:12px 16px;border-radius:8px">
<label for="user">用户名</label>
<input id="user" class="inp" maxlength="20" disabled>
<br>
<button onclick="submit()">登录</button>
</div>
转出来的 JSX:
{/* 登录卡片 */}
<div className="card" style={{ padding: '12px 16px', borderRadius: '8px' }}>
<label htmlFor="user">用户名</label>
<input id="user" className="inp" maxLength={20} disabled={true} />
<br />
<button onClick={submit}>登录</button>
</div>
class 都成了 className,for 成了 htmlFor,maxlength 驼峰成 maxLength,style 成了对象,disabled 补了值,<input> 和 <br> 自闭合,注释换了写法,onclick 驼峰成 onClick。这一段手工改大概要两分钟还容易漏,机器一遍过。
我自己的习惯
我接手设计师从 Figma 导出的 HTML 时,以前的流程是新建文件、粘代码、然后跟编译器斗,改完一个 class 报错下一个,前半小时全耗在查找替换上。现在我直接整份导出丢进转换器,一次转干净,再手工拆成组件、把写死的文案换成 props。省下来的不是那点机械劳动,是注意力,留给真正要想的组件边界划分。要提醒一句:工具只转换不净化,源码里的 onclick 会变成 onClick 留在输出里,<script> 也还在,发布前自己审一遍,尤其当 HTML 来自不可信来源。
需要这条捷径的话,直接用 HTML 转 JSX 工具,粘进去就出结果,全程在浏览器本地完成。转完发现样式还乱的话,顺手用 CSS 格式化工具 把抽出来的样式理一遍再回填。
Made by Toolora · Updated 2026-06-13