跳到主要内容

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
// jsx
function Demo(){
return <div className="box">内容</div>
}
  • 必须反复强调 <div className="box">内容</div> 不是 HTML 标签语句,它是一个 JSX 风格的 JavaScript 对象。
  • 为了统一风格,避免与 HTML、JavaScript 关键字冲突,JSX 规定:属性使用驼峰命名如 borderLeftonClicktabIndex
  • 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

ifforwhile...这些语句必须在 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>
);
}