JSX和JSX-Live
JS、JSX、JSX-Live 风格对比
JS 风格
jsdemo.js
// js 示例
function greet(name) {
return "Hello, " + name;
}
const user = "Alice";
console.log(greet(user));
JS特点
- 只用 JavaScript 语法。
- 没有 HTML 标签。
- 文件扩展名通常是
.js。 - 可以直接在浏览器
<script>或 Node.js 执行。
JSX 风格
JSX 是 React 的语法扩展,可以在 JS 里写 HTML 样式标签。
jsxdemo.jsx
// jsx 示例
import React from "react";
function Greeting({ name }) {
return <h1>Hello, {name}</h1>;
}
export default function App() {
const user = "Alice";
return <Greeting name={user} />;
}
JSX特点
- 支持
<tag>语法嵌入 JavaScript。 - JSX 必须通过 Babel 或类似工具编译成普通 JS 才能运行。示例中高亮行就是 JSX ,会被 Babel 编译为普通 JS 代码后运行。
- 文件扩展名通常是
.jsx(或者.tsx用于 TypeScript)。 - 可以在组件中直接使用
{}插入变量。 - JSX 本质上是 一个描述 UI 的 JavaScript 对象(React 元素对象),它本身不直接操作网页元素。React 会根据这个对象 计算差异,然后更新真实 DOM。
JSX-Live 风格
JSX-Live 用于文档或 Markdown 中直接运行 JSX 代码(如 react-live 或 Docusaurus live code block)。
在 Markdown 笔记中使用 jsx live 代码块,使用 Docusaurus 编译时会在页面中嵌入一个实时编辑器(如下),能够将代码块中的 JSX (React)代码实时编译和渲染。
jsx
// jsx-live 示例
function Demo() {
const [count, setCount] = React.useState(0);
return (
<div>
<p>点击次数: {count}</p>
<button onClick={() => setCount(count + 1)}>点击此处</button>
</div>
);
}
JSX-Live特点
- 代码块可直接渲染并交互。
- 不需要
export,也可以省略import React(有些文档环境会自动提供 React)。 - 一般只写组件内逻辑和 JSX 返回值。
- 更注重演示效果而非完整应用结构。
JSX 语法
important
JSX 只能有一个根标签。JSX-Live 不允许在同一个代码块内定义多个顶层函数。
标签语法
- JSX
- React
- JavaScript
jsx
// jsx
function Demo(){
return <div className="box">内容</div>
}
react
// 在 React 编译下,会被转换成类似下面的 JS 代码:
function Demo() {
return React.createElement(
"div", // 标签名
{ className: "box" }, // 属性对象
"内容" // 子元素(可以是字符串、数组或其他元素)
);
}
js
// 然后 React 在浏览器中会把这个对象 **渲染成真实 DOM**:
<div class="box">内容</div>
- 必须反复强调
<div className="box">内容</div>不是 HTML 标签语句,它是一个 JSX 风格的 JavaScript 对象。 - 为了统一风格,避免与 HTML、JavaScript 关键字冲突,JSX 规定:属性使用驼峰命名如
borderLeft、onClick、tabIndex。 class与 JavaScript 关键字冲突,要写成className。
表达式嵌入
JSX 是把 HTML 和 JavaScript 内容混杂在一起写的语句:HTML内容可以直接写,JavaScript 内容要写在 {} 中。
jsx
// jsx live
function Demo(){
const name = "在线知识库";
return <p>hello,{name}</p>;
}
oh, shit! 它看起来真的很奇怪。
看这个 JSX 语句:
jsx
// jsx
return <p>hello, {name}</p>;
乍一看,好像是在 JavaScript 里直接写了一个 HTML 标签。但实际上,这只是 JSX —— JavaScript 的语法扩展。它不是字符串,也不是 HTML,而是一个 模板,用来描述 <p> 元素的类型、属性和子节点。
编译后,JSX 会生成一个 JavaScript 对象(React 元素对象)。React 根据这个对象去创建或更新真实的 DOM,最终在浏览器里显示 <p> 标签和它的内容。
规则 1:花括号 {} 内可以放 任意 JS 表达式
- 变量:
{name} - 算术运算:
{1 + 2} - 函数调用:
{getTime()} - 三元运算符:
{isLogin ? "已登录" : "未登录"} - 数组映射:
{list.map(function(item){ return <li>{item}</li>; })}
规则 2:花括号 {} 不能放语句
warning
if、for、while...这些语句必须在 JSX 外部执行。
jsx
// jsx 错误写法
{if(isLogin) { return <span>已登录</span>; }}
规则 3:JSX 可以嵌套,但只有一个顶层元素
jsx
// jsx
function Demo() {
const name = "Liss";
return (
<div>
<h1>Hello, {name}</h1>
<p>欢迎使用 JSX Live</p>
</div>
);
}
规则 4:属性中也可以嵌入表达式
jsx
// jsx
const size = 24;
const el = <p style={{ fontSize: size + "px" }}>文本</p>;
// 或者
const el= <p style={{ fontSize: "24px"}}>文本</p>;
// 或者不写单位,react自动补上px
const el= <p style={{ fontSize: 24}}>文本</p>;
- 外层
{}:告诉 JSX 这是一个 JS 表达式 - 内层
{}:JS 表达式本身是一个对象字面量。注意style是对象,不能写成字符串"font-size:24px;",fontSize是 key,"24px"是value。
规则 5:循环渲染列表时,表达式必须返回 JSX 元素
jsx
const list = ["苹果", "香蕉"];
const el = (
<ul>
{list.map(function(item, index) {
return <li key={index}>{item}</li>;
})}
</ul>
);
多行写法要加括号
jsx
function Demo(){
return (
<div>
<h1>标题</h1>
<p>内容</p>
</div>
);
}
组件写法
jsx
function Demo(){
function Welcome(props) {
return <p>Hello, {props.name}</p>;
}
return <Welcome name="灵魂信息" />;
}
条件和循环
jsx
function ClockWithShichen() {
const [time, setTime] = React.useState(new Date());
// 每秒更新
React.useEffect(function() {
const timer = setInterval(function() {
setTime(new Date());
}, 1000);
return function() {
clearInterval(timer);
};
}, []);
const hours = time.getHours();
const minutes = time.getMinutes();
const seconds = time.getSeconds();
// 十二时辰对应索引
const shichen = [
"子时", "丑时", "寅时", "卯时", "辰时", "巳时",
"午时", "未时", "申时", "酉时", "戌时", "亥时"
];
function getShichenIndex(hour) {
if (hour === 23 || hour < 1) return 0;
return Math.floor((hour + 1) / 2);
}
const currentShichen = shichen[getShichenIndex(hours)];
return (
<div style={{ fontSize: "48px", color: "green" }}>
{hours.toString().padStart(2,"0")}:
{minutes.toString().padStart(2,"0")}:
{seconds.toString().padStart(2,"0")}
<span style={{ color: "#655", marginLeft: "20px" }}>
{currentShichen}
</span>
</div>
);
}
JSX-Live案例:待 办清单
jsx
function TodoApp() {
const [todos, setTodos] = React.useState([
{ id: 1, text: "学习 JSX", done: false },
{ id: 2, text: "写 Docusaurus 文档", done: true },
]);
const [input, setInput] = React.useState("");
// 增加待办
function addTodo() {
if (!input.trim()) return;
const newTodo = { id: Date.now(), text: input, done: false };
setTodos(todos.concat(newTodo));
setInput("");
}
// 删除待办
function removeTodo(id) {
setTodos(todos.filter(function(todo) { return todo.id !== id; }));
}
// 切换完成状态
function toggleDone(id) {
setTodos(todos.map(function(todo) {
if (todo.id === id) {
return { ...todo, done: !todo.done };
}
return todo;
}));
}
return (
<div style={{ maxWidth: "400px", margin: "10px" }}>
<h1>待办清单</h1>
<div style={{ marginBottom: "10px" }}>
<input
type="text"
value={input}
onChange={function(e) { setInput(e.target.value); }}
placeholder="输入新的待办项"
/>
<button onClick={addTodo}>添加</button>
</div>
<ul>
{todos.map(function(todo) {
return (
<li key={todo.id} style={{ marginBottom: "5px" }}>
<input
type="checkbox"
checked={todo.done}
onChange={function() { toggleDone(todo.id); }}
/>
<span style={{
textDecoration: todo.done ? "line-through" : "none",
marginLeft: "5px"
}}>
{todo.text}
</span>
<button
onClick={function() { removeTodo(todo.id); }}
style={{ marginLeft: "10px" }}
>
删除
</button>
</li>
);
})}
</ul>
</div>
);
}