首页 / Astro 教程 / 表达式与动态属性

Astro 教程

表达式与动态属性

本教程共 56 篇 · 第 7 篇 · 更新于 2026-08-07 · 约 10 分钟阅读

AstroAstro 教程JS 表达式动态属性class:listset:html模板语法

本节目标:学会在 .astro 模板里用 {} 写表达式、动态给标签加属性,并用 class:list 等指令拼出会变化的 HTML。

上一章说过,模板区不只写死 HTML,还能把脚本里的变量“插”进去。这一章就专门把模板里的“动态写法”拆开讲。学会了这些,你就能用一段模板,根据数据生成出不同的页面内容。

用花括号写表达式

在模板里,凡是想插入“算出来的值”,都用一个花括号 {} 包起来。它和 React 的 JSX 很像,但 Astro 没有引入额外框架,只是借了这种直观的写法。

脚本里定义的变量,直接 {变量名} 就能用:

---
const title = "我的小站";
const count = 3;
---

<h1>{title}</h1>
<p>你有 {count} 条新消息</p>

花括号里不只能放变量,还能放一整段 JavaScript 表达式:做运算、调函数、三元判断都行。

---
const price = 100;
const isVIP = true;
---

<p>应付:{price * (isVIP ? 0.8 : 1)} 元</p>
<p>{isVIP ? "尊贵的会员" : "欢迎光临"}</p>
Tip

花括号里尽量写“一行能算完”的小表达式。要是逻辑太长,建议先在前面的 frontmatter 里算好、存进变量,模板里只负责展示。这样模板清爽,也好排查问题。

用 map 循环出列表

最常见的动态需求,是把一个数组渲染成一串 <li>、一排卡片。这时在 { } 里用数组的 .map() 即可,写法和 JSX 几乎一样。

---
const fruits = ["苹果", "香蕉", "橙子"];
---

<ul>
  {fruits.map((name) => <li>{name}</li>)}
</ul>

如果数组里是对象,就取对象的字段:

---
const posts = [
  { title: "第一篇", author: "码上学" },
  { title: "第二篇", author: "小明" },
];
---

<ul>
  {posts.map((p) => (
    <li>{p.title} —— 作者:{p.author}</li>
  ))}
</ul>

注意:这里 map 返回的是一组 JSX 风格的标签,直接写在 { } 里就行,Astro 会替你拼成 HTML。

动态绑定属性

标签的属性也能动态。把属性值用 {} 包起来,里面写表达式,属性就跟着数据走。

---
const imgUrl = "/photos/cover.jpg";
const altText = "封面图";
---

<img src={imgUrl} alt={altText} />

布尔属性也一样。比如一个按钮要不要禁用,由变量决定:

---
const soldOut = true;
---

<button disabled={soldOut}>立即购买</button>

soldOuttrue,渲染出来就是 <button disabled>,按钮变灰不可点;为 false 时,这个属性直接不出现。Astro 会替你处理好布尔属性的细节,不用自己拼字符串。

用 class:list 拼出动态 class

给元素加 class 是最常遇到的动态场景。比如一个盒子,平时是蓝边,遇到“红色警报”状态要变红边。一个个字符串拼容易出错,Astro 给了专门的 class:list 指令来优雅处理。

---
const { isRed } = Astro.props;
---

<!-- isRed 为真,class 是 "box red";为假,只有 "box" -->
<div class:list={['box', { red: isRed }]}>
  <slot />
</div>

<style>
  .box { border: 1px solid blue; }
  .red { border-color: red; }
</style>

class:list 接收的是一个数组,数组里可以混着:

  • 普通字符串,比如 'box',原样加上;
  • 对象,比如 { red: isRed },只有值为真的键名才会被加进去。

它还能组合多个来源,写得再长也不乱。这是 Astro 模板里拼 class 的首选方式,比手写字符串拼接稳妥得多。

Note

class:list 属于 Astro 的模板指令。第 11 章讲样式时还会提到它——因为它常和组件级样式配合,决定一个元素到底套哪套样式。两处讲的是同一件工具,角度不同。

set:html 直接插入 HTML 字符串

有时你手里已经是一段 HTML 字符串(比如从接口拿来的富文本),想原样塞进页面,用 set:html 指令:

---
const rich = "<strong>加粗</strong>的文字";
---

<p set:html={rich}></p>

渲染后,<p> 里就是真正的加粗文字,而不是把标签当文本显示。

Warning

set:html 会把字符串当 HTML 执行。如果内容来自不可信的用户输入,直接用有安全风险(比如被注入恶意脚本)。只在你确定内容安全时用它。

条件渲染:该不该显示

模板里常要根据数据决定“某段 HTML 显不显示”。用 JS 表达式里的 && 或三元就能做。

&&:条件为真,才渲染它后面的内容。

---
const isLogin = false;
---

{isLogin && <p>欢迎回来,会员!</p>}

isLogin 为假时,整个表达式算出来是 false,Astro 不输出任何东西;为真时才把那段 <p> 渲染出来。

用三元:二选一,比 && 更灵活。

---
const score = 85;
---

<p>{score >= 60 ? "及格啦" : "再接再厉"}</p>
Tip

条件渲染写多了,模板容易变长。逻辑复杂的“显隐”,建议先在 frontmatter 里算好一个布尔变量,模板里只留 {showX && <…/>},清爽好维护。

几个容易踩的小坑

  1. 花括号只在“文本位置”和“属性值”里生效。你想在标签名、属性名里用动态值,Astro 不支持,得换思路(比如用条件渲染拼不同标签)。
  2. {} 里写的是“表达式”不是“语句”。不能写 if (...) {} 这种完整语句,要用三元或 && 表达。
  3. 字符串和变量混写时,变量用 {},纯文字直接写:<p>共 {count} 条</p> 才对,别写成 <p>共 count 条</p>——后者 count 会被当成普通文字。
  4. 表达式里尽量别直接写 >< 这类符号,避免被误解析成标签;纯文本展示一般没事,涉及判断时用 .gt.lt 或把逻辑挪到 frontmatter 里更稳妥。

表达式里也能调用函数

脚本里定义的函数,模板里可以直接调用,把格式化之类的逻辑收进函数,模板只管调用:

---
function formatPrice(n) {
  return "¥" + n.toFixed(2);
}
const price = 12.5;
---

<p>价格:{formatPrice(price)}</p>

这样模板保持干净,复杂计算都躲在 frontmatter 里。

用模板字符串拼属性值

一个属性要由几段拼成时,用 JS 模板字符串(反引号)很方便:

---
const base = "https://img.example.com/";
const file = "cover.jpg";
---

<img src={`${base}${file}`} alt="封面" />

反引号里用 ${} 插值,适合拼路径、拼链接这类场景。普通字符串拼接(+ 号)也行,但模板字符串更直观、不容易漏引号。

set:text:插入纯文本更安全

set:html 相对的,是 set:text。它把字符串当「纯文本」插进去,Astro 会自动帮你转义,不会把里面的 <> 当成标签:

---
const text = "<script>alert(1)</script>";
---
<p set:text={text}></p>

渲染后页面上看到的就是一行字 <script>alert(1)</script>,而不是真去执行脚本。所以:内容是用户给的、不信任的,优先用 set:text;只有你百分百信任、且确实要当 HTML 渲染时,才用 set:html

表达式里的大小括号要注意

{} 里写表达式很方便,但有两个小习惯值得记牢:

  1. 纯字符串拼接时,变量用 {},文字直接写。比如 <p>共 {count} 条</p>。若你写成 <p>共 count 条</p>count 会被当成普通汉字显示,不是变量。
  2. 表达式里尽量别直接写 >< 这种符号,浏览器可能误以为是标签的开头。比如做比较,最好把判断挪到 frontmatter 里算好布尔值,模板里只放结果;或者改用 .gt.lt 这类写法避开尖括号。

注释怎么写

模板里两种注释都认:

<!-- 这是 HTML 注释,会出现在最终源码里 -->
{/* 这是 JS 风格注释,不会进最终页面 */}

写给自己看的说明,用 {/* */} 更干净,发布后用户看不到。

小结

模板区的动态能力,核心就这几样:用 {} 插表达式、用 .map() 出列表、用 {} 绑动态属性、用 class:list 拼 class、用 set:html 插原始 HTML。它们都跑在“服务器算好再发 HTML”的节奏里,所以写起来直观、出 Bug 也少。下一章讲怎么把数据从外面“传进”组件——也就是组件的 Props 与 TypeScript 类型。