JSX语法 #
一、JSX 基础 #
1.1 什么是 JSX #
JSX 是 JavaScript 的语法扩展,允许在 JavaScript 中编写类似 HTML 的代码。Solid 使用 JSX 来描述 UI。
jsx
// JSX 代码
const element = <h1>Hello, Solid!</h1>;
// 编译后
const element = document.createElement('h1');
element.textContent = 'Hello, Solid!';
1.2 JSX 与 HTML 的区别 #
| 特性 | JSX | HTML |
|---|---|---|
| class 属性 | className | class |
| for 属性 | htmlFor | for |
| style 属性 | 对象 | 字符串 |
| 事件绑定 | onClick | onclick |
| 自定义属性 | 小驼峰 | 短横线 |
二、表达式插值 #
2.1 基本插值 #
使用 {} 插入 JavaScript 表达式:
jsx
function Greeting(props) {
const name = 'Solid';
const version = 1.8;
return (
<div>
<h1>Hello, {name}!</h1>
<p>Version: {version}</p>
<p>Time: {new Date().toLocaleTimeString()}</p>
<p>Sum: {1 + 2 + 3}</p>
</div>
);
}
2.2 Signal 插值 #
jsx
function Counter() {
const [count, setCount] = createSignal(0);
return (
<div>
<p>Count: {count()}</p>
<p>Doubled: {count() * 2}</p>
<p>Message: {count() > 10 ? 'Large' : 'Small'}</p>
</div>
);
}
2.3 函数调用 #
jsx
function formatName(user) {
return `${user.firstName} ${user.lastName}`;
}
function Profile() {
const user = { firstName: 'John', lastName: 'Doe' };
return (
<div>
<p>Name: {formatName(user)}</p>
<p>Upper: {user.firstName.toUpperCase()}</p>
</div>
);
}
三、属性绑定 #
3.1 静态属性 #
jsx
<div id="main" className="container">
<img src="image.png" alt="Description" />
<a href="https://example.com" target="_blank">
Link
</a>
</div>
3.2 动态属性 #
jsx
function ImageGallery(props) {
return (
<div>
<img
src={props.imageUrl}
alt={props.description}
width={props.width}
height={props.height}
/>
<a href={props.linkUrl}>
{props.linkText}
</a>
</div>
);
}
3.3 展开属性 #
jsx
function Button(props) {
return (
<button {...props}>
{props.children}
</button>
);
}
// 使用
<Button
className="primary"
onClick={handleClick}
disabled={isLoading}
>
Click me
</Button>
3.4 class 属性 #
jsx
// 使用 className
<div className="container main">
// 动态 class
<div className={`btn ${isActive() ? 'active' : ''}`}>
// 使用 classList(推荐)
<div classList={{
btn: true,
active: isActive(),
disabled: isDisabled()
}}>
3.5 style 属性 #
jsx
// 对象形式
<div style={{
color: 'red',
fontSize: '16px',
backgroundColor: '#f0f0f0'
}}>
// 动态样式
<div style={{
color: isActive() ? 'green' : 'gray',
transform: `translateX(${offset()}px)`
}}>
// CSS 变量
<div style={{
'--main-color': themeColor(),
'--padding': '20px'
}}>
四、组件 #
4.1 定义组件 #
jsx
// 函数组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// 箭头函数
const Goodbye = (props) => <h1>Goodbye, {props.name}</h1>;
4.2 使用组件 #
jsx
function App() {
return (
<div>
<Welcome name="Alice" />
<Welcome name="Bob" />
<Goodbye name="Charlie" />
</div>
);
}
4.3 组件组合 #
jsx
function Card(props) {
return (
<div className="card">
<div className="card-header">
{props.title}
</div>
<div className="card-body">
{props.children}
</div>
<div className="card-footer">
{props.footer}
</div>
</div>
);
}
function App() {
return (
<Card
title="Welcome"
footer={<button>Submit</button>}
>
<p>This is the card content.</p>
<p>More content here.</p>
</Card>
);
}
五、条件渲染 #
5.1 三元表达式 #
jsx
function Status(props) {
return (
<div>
{props.isLoggedIn ? (
<p>Welcome back!</p>
) : (
<p>Please log in.</p>
)}
</div>
);
}
5.2 逻辑与 (&&) #
jsx
function Notifications(props) {
return (
<div>
{props.hasUnread && (
<span className="badge">
{props.unreadCount}
</span>
)}
</div>
);
}
5.3 Show 组件(推荐) #
Solid 提供了 Show 组件用于条件渲染:
jsx
import { Show } from 'solid-js';
function Profile(props) {
const [user, setUser] = createSignal(null);
return (
<div>
<Show
when={user()}
fallback={<p>Loading...</p>}
>
{(userData) => (
<div>
<h1>{userData().name}</h1>
<p>{userData().email}</p>
</div>
)}
</Show>
</div>
);
}
5.4 Switch 组件 #
jsx
import { Switch, Match } from 'solid-js';
function StatusMessage(props) {
return (
<Switch fallback={<p>Unknown status</p>}>
<Match when={props.status === 'loading'}>
<p>Loading...</p>
</Match>
<Match when={props.status === 'success'}>
<p>Success!</p>
</Match>
<Match when={props.status === 'error'}>
<p>Error occurred!</p>
</Match>
</Switch>
);
}
六、列表渲染 #
6.1 map 方法 #
jsx
function UserList(props) {
return (
<ul>
{props.users.map(user => (
<li key={user.id}>
{user.name}
</li>
))}
</ul>
);
}
6.2 For 组件(推荐) #
Solid 提供了 For 组件用于高效列表渲染:
jsx
import { For } from 'solid-js';
function UserList(props) {
return (
<ul>
<For each={props.users}>
{(user, index) => (
<li>
{index()}: {user.name}
</li>
)}
</For>
</ul>
);
}
6.3 Index 组件 #
当需要基于索引更新时使用:
jsx
import { Index } from 'solid-js';
function NumberList() {
const [numbers, setNumbers] = createSignal([1, 2, 3, 4, 5]);
return (
<ul>
<Index each={numbers()}>
{(number, index) => (
<li>
Index {index}: {number()}
</li>
)}
</Index>
</ul>
);
}
6.4 For vs Index #
text
For 组件
├── 基于 key 追踪
├── 适合对象数组
├── 重排序时高效
└── 数据变化时,更新对应项
Index 组件
├── 基于索引追踪
├── 适合原始值数组
├── 更新时替换整个元素
└── 数据变化时,更新对应位置
七、事件处理 #
7.1 基本事件 #
jsx
function Button() {
const handleClick = () => {
console.log('Button clicked');
};
return (
<button onClick={handleClick}>
Click me
</button>
);
}
7.2 事件对象 #
jsx
function Form() {
const handleSubmit = (e) => {
e.preventDefault();
console.log('Form submitted');
};
const handleInput = (e) => {
console.log('Input value:', e.target.value);
};
return (
<form onSubmit={handleSubmit}>
<input onInput={handleInput} />
<button type="submit">Submit</button>
</form>
);
}
7.3 传递参数 #
jsx
function TodoList() {
const [todos, setTodos] = createSignal([
{ id: 1, text: 'Learn Solid' },
{ id: 2, text: 'Build app' }
]);
const deleteTodo = (id) => {
setTodos(prev => prev.filter(t => t.id !== id));
};
return (
<ul>
<For each={todos()}>
{(todo) => (
<li>
{todo.text}
<button onClick={() => deleteTodo(todo.id)}>
Delete
</button>
</li>
)}
</For>
</ul>
);
}
7.4 事件修饰符 #
Solid 不支持 Vue 风格的事件修饰符,需要手动处理:
jsx
// 阻止默认行为
<form onSubmit={(e) => {
e.preventDefault();
handleSubmit();
}}>
// 阻止冒泡
<div onClick={(e) => {
e.stopPropagation();
handleClick();
}}>
// 只触发一次
<button onClick={(e) => {
handleClick();
e.target.disabled = true;
}}>
八、双向绑定 #
8.1 受控组件 #
jsx
function Input() {
const [value, setValue] = createSignal('');
return (
<div>
<input
value={value()}
onInput={(e) => setValue(e.target.value)}
/>
<p>You typed: {value()}</p>
</div>
);
}
8.2 使用 bind #
Solid 支持 bind:value 简化双向绑定:
jsx
function Input() {
const [value, setValue] = createSignal('');
return (
<div>
<input bind:value={value} />
<p>You typed: {value()}</p>
</div>
);
}
8.3 其他绑定 #
jsx
function Form() {
const [text, setText] = createSignal('');
const [checked, setChecked] = createSignal(false);
const [selected, setSelected] = createSignal('option1');
return (
<form>
<input bind:value={text} />
<input type="checkbox" bind:checked={checked} />
<select bind:value={selected}>
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
</select>
</form>
);
}
九、Fragment #
9.1 使用 Fragment #
jsx
import { Fragment } from 'solid-js';
function List() {
return (
<Fragment>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</Fragment>
);
}
// 简写形式
function List() {
return (
<>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</>
);
}
9.2 带键的 Fragment #
jsx
function TableRows() {
return (
<>
<tr key="header">
<th>Name</th>
<th>Age</th>
</tr>
<For each={data()}>
{(item) => (
<tr key={item.id}>
<td>{item.name}</td>
<td>{item.age}</td>
</tr>
)}
</For>
</>
);
}
十、总结 #
10.1 JSX 核心规则 #
- 单根元素:组件返回单个根元素
- 闭合标签:所有标签必须闭合
- 驼峰命名:属性使用驼峰命名法
- 表达式插值:使用
{}插入表达式 - 组件大写:组件名首字母大写
10.2 Solid 特有语法 #
| 语法 | 说明 |
|---|---|
classList |
动态 class 绑定 |
bind:value |
双向绑定 |
Show |
条件渲染组件 |
For |
列表渲染组件 |
Index |
索引列表渲染 |
Switch/Match |
多条件渲染 |
10.3 最佳实践 #
- 使用
Show替代三元表达式 - 使用
For渲染列表 - 使用
classList管理动态类名 - 使用
bind:简化双向绑定 - 保持组件简洁,拆分复杂逻辑
最后更新:2026-03-28