条件渲染 #

一、条件渲染概述 #

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