← 返回目录 | 下一课:组件基础 →

第2课: JSX语法详解

JavaScript的扩展语法与React开发基础

🎯 学习目标

1. JSX是什么?

JSX定义:JSX是JavaScript的语法扩展,它允许我们在JavaScript代码中编写类似HTML的标记。JSX让React组件的编写更加直观和简洁。

JSX vs 纯JavaScript

纯JavaScript方式

// 使用React.createElement
const element = React.createElement(
    'h1',
    {className: 'greeting'},
    'Hello, world!'
);

JSX方式

// 使用JSX语法
const element = (
    <h1 className="greeting">
        Hello, world!
    </h1>
);

重要概念:JSX不是必须的,但强烈推荐使用。它会被编译成普通的JavaScript函数调用,最终生成React元素。

2. JSX基本语法规则

2.1 标签必须闭合

规则:所有标签都必须正确闭合,包括自闭合标签。

// ✅ 正确
<div>内容</div>
<img src="image.jpg" />
<input type="text" />

// ❌ 错误
<div>内容  // 缺少闭合标签
<img src="image.jpg">  // 自闭合标签需要斜杠

2.2 必须有一个根元素

规则:JSX表达式必须有一个根元素,或者使用Fragment。

// ✅ 正确 - 使用div包裹
return (
    <div>
        <h1>标题</h1>
        <p>内容</p>
    </div>
);

// ✅ 正确 - 使用Fragment
return (
    <>
        <h1>标题</h1>
        <p>内容</p>
    </>
);

// ❌ 错误 - 多个根元素
return (
    <h1>标题</h1>
    <p>内容</p>
);

2.3 使用className代替class

注意:由于class是JavaScript的保留字,在JSX中使用className来设置CSS类。

// ✅ 正确
<div className="container">内容</div>

// ❌ 错误
<div class="container">内容</div>

3. 在JSX中嵌入JavaScript表达式

核心特性:可以在JSX中使用花括号{}来嵌入任何有效的JavaScript表达式。

3.1 变量和表达式

function Welcome() {
    const name = "张三";
    const age = 25;
    const isStudent = true;
    
    return (
        <div>
            <h1>欢迎, {name}!</h1>
            <p>年龄: {age}</p>
            <p>状态: {isStudent ? '学生' : '非学生'}</p>
            <p>明年年龄: {age + 1}</p>
        </div>
    );
}

3.2 函数调用

function formatName(user) {
    return user.firstName + ' ' + user.lastName;
}

function UserCard() {
    const user = {
        firstName: '李',
        lastName: '四'
    };
    
    return (
        <div>
            <h2>用户: {formatName(user)}</h2>
            <p>时间: {new Date().toLocaleTimeString()}</p>
        </div>
    );
}

4. JSX的条件渲染

4.1 使用三元运算符

function LoginButton({ isLoggedIn }) {
    return (
        <div>
            {isLoggedIn ? (
                <button>退出登录</button>
            ) : (
                <button>登录</button>
            )}
        </div>
    );
}

4.2 使用逻辑与运算符

function Notification({ message, showNotification }) {
    return (
        <div>
            {showNotification && (
                <div className="notification">
                    {message}
                </div>
            )}
        </div>
    );
}

4.3 使用if语句(在JSX外部)

function Greeting({ isMorning }) {
    let greeting;
    
    if (isMorning) {
        greeting = <h1>早上好!</h1>;
    } else {
        greeting = <h1>晚上好!</h1>;
    }
    
    return <div>{greeting}</div>;
}

5. JSX的列表渲染

5.1 使用map方法

function TodoList() {
    const todos = [
        { id: 1, text: '学习React', completed: false },
        { id: 2, text: '写代码', completed: true },
        { id: 3, text: '阅读文档', completed: false }
    ];
    
    return (
        <ul>
            {todos.map(todo => (
                <li key={todo.id}>
                    {todo.text} - {todo.completed ? '已完成' : '未完成'}
                </li>
            ))}
        </ul>
    );
}

重要提示:列表中的每个元素都需要一个唯一的key属性,这有助于React识别哪些项目发生了变化。

6. JSX中的样式处理

6.1 内联样式

function StyledComponent() {
    const boxStyle = {
        backgroundColor: '#f0f0f0',
        padding: '20px',
        border: '1px solid #ccc',
        borderRadius: '5px',
        margin: '10px 0'
    };
    
    return (
        <div style={boxStyle}>
            <h2 style={{color: '#61DAFB', fontSize: '24px'}}>
                带样式的组件
            </h2>
            <p style={{color: '#666', lineHeight: '1.6'}}>
                这是一个带有内联样式的段落。
            </p>
        </div>
    );
}

样式对象:内联样式需要使用驼峰命名法(如backgroundColor),而不是CSS的连字符写法(background-color)。

7. JSX中的事件处理

function InteractiveButton() {
    const handleClick = () => {
        alert('按钮被点击了!');
    };
    
    const handleMouseOver = (event) => {
        event.target.style.backgroundColor = '#61DAFB';
    };
    
    const handleMouseOut = (event) => {
        event.target.style.backgroundColor = '';
    };
    
    return (
        <button 
            onClick={handleClick}
            onMouseOver={handleMouseOver}
            onMouseOut={handleMouseOut}
            style={{
                padding: '10px 20px',
                border: 'none',
                borderRadius: '5px',
                cursor: 'pointer'
            }}
        >
            点击我试试!
        </button>
    );
}

💡 动手练习

任务:创建一个商品列表组件

要求:

// 参考答案
function ProductList() {
    const products = [
        { id: 1, name: 'iPhone', price: 5999, stock: 10 },
        { id: 2, name: 'MacBook', price: 9999, stock: 5 },
        { id: 3, name: 'iPad', price: 3299, stock: 0 }
    ];
    
    const handleClick = (product) => {
        alert(`商品: ${product.name}\n价格: ¥${product.price}\n库存: ${product.stock}`);
    };
    
    return (
        <div>
            <h2>商品列表</h2>
            {products.map(product => (
                <div 
                    key={product.id}
                    onClick={() => handleClick(product)}
                    style={{
                        border: '1px solid #ddd',
                        padding: '15px',
                        margin: '10px 0',
                        borderRadius: '5px',
                        cursor: 'pointer',
                        backgroundColor: product.stock === 0 ? '#ffebee' : '#f9f9f9',
                        color: product.stock === 0 ? '#f44336' : 'inherit'
                    }}
                >
                    <h3>{product.name}</h3>
                    <p>价格: ¥{product.price}</p>
                    <p>库存: {product.stock}</p>
                </div>
            ))}
        </div>
    );
}

📝 关键概念总结