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 核心规则 #

  1. 单根元素:组件返回单个根元素
  2. 闭合标签:所有标签必须闭合
  3. 驼峰命名:属性使用驼峰命名法
  4. 表达式插值:使用 {} 插入表达式
  5. 组件大写:组件名首字母大写

10.2 Solid 特有语法 #

语法 说明
classList 动态 class 绑定
bind:value 双向绑定
Show 条件渲染组件
For 列表渲染组件
Index 索引列表渲染
Switch/Match 多条件渲染

10.3 最佳实践 #

  • 使用 Show 替代三元表达式
  • 使用 For 渲染列表
  • 使用 classList 管理动态类名
  • 使用 bind: 简化双向绑定
  • 保持组件简洁,拆分复杂逻辑
最后更新:2026-03-28