条件渲染 #
一、条件渲染概述 #
1.1 什么是条件渲染? #
条件渲染允许根据条件动态显示或隐藏内容。Astro 提供多种条件渲染方式:
astro
---
const isLoggedIn = true;
const role = 'admin';
---
<!-- 方式一:逻辑与运算符 -->
{isLoggedIn && <p>欢迎回来</p>}
<!-- 方式二:三元表达式 -->
<p>{isLoggedIn ? '已登录' : '未登录'}</p>
<!-- 方式三:条件语句 -->
{isLoggedIn ? (
<p>欢迎回来</p>
) : (
<p>请先登录</p>
)}
二、逻辑与运算符(&&) #
2.1 基本用法 #
astro
---
const showBanner = true;
const hasNotification = false;
---
{showBanner && <div class="banner">公告内容</div>}
{hasNotification && <div class="notification">新消息</div>}
2.2 显示/隐藏元素 #
astro
---
const features = {
darkMode: true,
notifications: false,
analytics: true
};
---
{features.darkMode && (
<button class="theme-toggle">切换主题</button>
)}
{features.notifications && (
<div class="notification-panel">通知面板</div>
)}
{features.analytics && (
<div class="analytics-widget">统计组件</div>
)}
2.3 列表条件显示 #
astro
---
const items = [
{ id: 1, name: '商品A', inStock: true },
{ id: 2, name: '商品B', inStock: false },
{ id: 3, name: '商品C', inStock: true },
];
---
<ul>
{items.map(item => (
<li>
{item.name}
{item.inStock && <span class="badge">有货</span>}
{!item.inStock && <span class="badge out">缺货</span>}
</li>
))}
</ul>
2.4 注意事项 #
astro
---
const count = 0;
const items = [];
---
<!-- ⚠️ 注意:0 会显示出来 -->
{count && <p>数量: {count}</p>}
<!-- 输出: 0 -->
<!-- ✅ 正确做法:使用布尔转换 -->
{count > 0 && <p>数量: {count}</p>}
<!-- 无输出 -->
<!-- ⚠️ 空数组是真值 -->
{items.length && <p>有 {items.length} 个项目</p>}
<!-- 输出: 0 -->
<!-- ✅ 正确做法 -->
{items.length > 0 && <p>有 {items.length} 个项目</p>}
三、三元表达式 #
3.1 基本用法 #
astro
---
const isLoggedIn = true;
const theme = 'dark';
---
<p>{isLoggedIn ? '欢迎回来' : '请先登录'}</p>
<p>当前主题: {theme === 'dark' ? '深色' : '浅色'}</p>
3.2 条件渲染组件 #
astro
---
const isLoading = false;
---
{isLoading ? (
<div class="loading">加载中...</div>
) : (
<div class="content">内容已加载</div>
)}
3.3 条件属性 #
astro
---
const isActive = true;
const isDisabled = false;
---
<button
class={`btn ${isActive ? 'active' : ''}`}
disabled={isDisabled}
>
{isDisabled ? '不可用' : '点击'}
</button>
3.4 嵌套三元 #
astro
---
const role = 'admin';
---
<p>
用户类型: {
role === 'admin' ? '管理员' :
role === 'editor' ? '编辑者' :
role === 'viewer' ? '浏览者' : '未知'
}
</p>
3.5 复杂条件 #
astro
---
const user = {
isLoggedIn: true,
role: 'admin',
hasPermission: true
};
---
{user.isLoggedIn && user.role === 'admin' ? (
<div class="admin-panel">管理面板</div>
) : user.isLoggedIn ? (
<div class="user-panel">用户面板</div>
) : (
<div class="login-prompt">请登录</div>
)}
四、条件语句 #
4.1 使用变量存储结果 #
astro
---
const status = 'loading';
let content;
if (status === 'loading') {
content = <div class="loading">加载中...</div>;
} else if (status === 'error') {
content = <div class="error">加载失败</div>;
} else {
content = <div class="success">加载成功</div>;
}
---
{content}
4.2 函数返回内容 #
astro
---
function renderStatus(status) {
switch (status) {
case 'loading':
return <div class="loading">加载中...</div>;
case 'error':
return <div class="error">出错了</div>;
case 'success':
return <div class="success">成功</div>;
default:
return <div class="unknown">未知状态</div>;
}
}
const status = 'success';
---
{renderStatus(status)}
4.3 状态映射 #
astro
---
const statusMap = {
pending: { text: '待处理', class: 'status-pending' },
processing: { text: '处理中', class: 'status-processing' },
completed: { text: '已完成', class: 'status-completed' },
cancelled: { text: '已取消', class: 'status-cancelled' }
};
const status = 'completed';
const statusInfo = statusMap[status] || { text: '未知', class: 'status-unknown' };
---
<span class={statusInfo.class}>{statusInfo.text}</span>
五、条件属性 #
5.1 条件 class #
astro
---
const isActive = true;
const isDisabled = false;
const size = 'large';
---
<!-- 使用 class:list -->
<button class:list={[
'btn',
{ active: isActive },
{ disabled: isDisabled },
`btn-${size}`
]}>
按钮
</button>
<!-- 输出: <button class="btn active btn-large">按钮</button> -->
5.2 条件 style #
astro
---
const theme = 'dark';
const primaryColor = theme === 'dark' ? '#ffffff' : '#000000';
---
<div style={`color: ${primaryColor}`}>
文本内容
</div>
5.3 条件属性存在 #
astro
---
const isRequired = true;
const isReadonly = false;
---
<input
type="text"
required={isRequired}
readonly={isReadonly}
/>
<!-- 输出: <input type="text" required /> -->
六、实际应用场景 #
6.1 用户认证状态 #
astro
---
const user = {
isLoggedIn: true,
name: '张三',
avatar: '/avatar.jpg'
};
---
<header class="header">
{user.isLoggedIn ? (
<div class="user-info">
<img src={user.avatar} alt={user.name} />
<span>{user.name}</span>
<button>退出</button>
</div>
) : (
<div class="auth-buttons">
<button>登录</button>
<button>注册</button>
</div>
)}
</header>
6.2 加载状态 #
astro
---
const state = {
isLoading: false,
error: null,
data: [
{ id: 1, title: '文章一' },
{ id: 2, title: '文章二' }
]
};
---
<div class="content">
{state.isLoading && (
<div class="loading">
<span class="spinner"></span>
加载中...
</div>
)}
{state.error && (
<div class="error">
错误: {state.error}
<button>重试</button>
</div>
)}
{!state.isLoading && !state.error && state.data.length > 0 && (
<ul class="list">
{state.data.map(item => (
<li key={item.id}>{item.title}</li>
))}
</ul>
)}
{!state.isLoading && !state.error && state.data.length === 0 && (
<div class="empty">暂无数据</div>
)}
</div>
6.3 权限控制 #
astro
---
const user = {
role: 'editor',
permissions: ['read', 'write']
};
function hasPermission(permission) {
return user.permissions.includes(permission);
}
---
<article>
<h1>文章标题</h1>
<p>文章内容...</p>
{hasPermission('write') && (
<div class="actions">
<button>编辑</button>
</div>
)}
{user.role === 'admin' && (
<div class="admin-actions">
<button>删除</button>
<button>置顶</button>
</div>
)}
</article>
6.4 表单验证 #
astro
---
const form = {
values: {
email: 'test@example.com',
password: ''
},
errors: {
email: '',
password: '密码不能为空'
},
touched: {
email: true,
password: true
}
};
---
<form>
<div class="form-group">
<input
type="email"
value={form.values.email}
class={form.errors.email && form.touched.email ? 'error' : ''}
/>
{form.errors.email && form.touched.email && (
<span class="error-message">{form.errors.email}</span>
)}
</div>
<div class="form-group">
<input
type="password"
value={form.values.password}
class={form.errors.password && form.touched.password ? 'error' : ''}
/>
{form.errors.password && form.touched.password && (
<span class="error-message">{form.errors.password}</span>
)}
</div>
<button
type="submit"
disabled={Object.values(form.errors).some(Boolean)}
>
提交
</button>
</form>
6.5 响应式布局 #
astro
---
const device = {
isMobile: false,
isTablet: true,
isDesktop: false
};
---
<div class="layout">
{device.isMobile && (
<nav class="mobile-nav">
<button>菜单</button>
</nav>
)}
{(device.isTablet || device.isDesktop) && (
<nav class="sidebar">
<a href="/">首页</a>
<a href="/blog">博客</a>
<a href="/about">关于</a>
</nav>
)}
<main class="content">
{device.isDesktop && <aside class="toc">目录</aside>}
<article>内容</article>
</main>
</div>
七、最佳实践 #
7.1 保持条件简洁 #
astro
---
// ✅ 好的做法:提取复杂条件
const canEdit = user.isLoggedIn &&
(user.role === 'admin' || user.role === 'editor');
const canDelete = user.isLoggedIn && user.role === 'admin';
---
{canEdit && <button>编辑</button>}
{canDelete && <button>删除</button>}
---
// ❌ 不好的做法:复杂条件直接写在模板中
---
{user.isLoggedIn && (user.role === 'admin' || user.role === 'editor') && (
<button>编辑</button>
)}
7.2 使用枚举替代魔法值 #
astro
---
// ✅ 好的做法:使用枚举
const Status = {
PENDING: 'pending',
PROCESSING: 'processing',
COMPLETED: 'completed'
};
const status = Status.COMPLETED;
const statusLabels = {
[Status.PENDING]: '待处理',
[Status.PROCESSING]: '处理中',
[Status.COMPLETED]: '已完成'
};
---
<p>{statusLabels[status]}</p>
7.3 避免深层嵌套 #
astro
---
// ✅ 好的做法:使用函数或组件
function renderContent({ isLoading, error, data }) {
if (isLoading) return <Loading />;
if (error) return <Error message={error} />;
if (!data.length) return <Empty />;
return <DataList data={data} />;
}
---
{renderContent(state)}
八、总结 #
条件渲染核心要点:
text
┌─────────────────────────────────────────────────────┐
│ 条件渲染要点 │
├─────────────────────────────────────────────────────┤
│ │
│ && 运算符 条件为真时显示内容 │
│ │
│ 三元表达式 条件为真/假显示不同内容 │
│ │
│ 条件语句 复杂条件逻辑处理 │
│ │
│ 条件属性 动态 class、style 等 │
│ │
│ 状态映射 使用对象映射替代多重条件 │
│ │
└─────────────────────────────────────────────────────┘
下一步,让我们学习 列表渲染,掌握循环渲染列表数据的方法!
最后更新:2026-03-28