表达式与动态属性
本教程共 56 篇 · 第 7 篇 · 更新于 2026-08-07 · 约 10 分钟阅读
本节目标:学会在
.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>
当 soldOut 为 true,渲染出来就是 <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 && <…/>},清爽好维护。
几个容易踩的小坑
- 花括号只在“文本位置”和“属性值”里生效。你想在标签名、属性名里用动态值,Astro 不支持,得换思路(比如用条件渲染拼不同标签)。
{}里写的是“表达式”不是“语句”。不能写if (...) {}这种完整语句,要用三元或&&表达。- 字符串和变量混写时,变量用
{},纯文字直接写:<p>共 {count} 条</p>才对,别写成<p>共 count 条</p>——后者count会被当成普通文字。 - 表达式里尽量别直接写
>、<这类符号,避免被误解析成标签;纯文本展示一般没事,涉及判断时用.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。
表达式里的大小括号要注意
{} 里写表达式很方便,但有两个小习惯值得记牢:
- 纯字符串拼接时,变量用
{},文字直接写。比如<p>共 {count} 条</p>。若你写成<p>共 count 条</p>,count会被当成普通汉字显示,不是变量。 - 表达式里尽量别直接写
>、<这种符号,浏览器可能误以为是标签的开头。比如做比较,最好把判断挪到 frontmatter 里算好布尔值,模板里只放结果;或者改用.gt、.lt这类写法避开尖括号。
注释怎么写
模板里两种注释都认:
<!-- 这是 HTML 注释,会出现在最终源码里 -->
{/* 这是 JS 风格注释,不会进最终页面 */}
写给自己看的说明,用 {/* */} 更干净,发布后用户看不到。
小结
模板区的动态能力,核心就这几样:用 {} 插表达式、用 .map() 出列表、用 {} 绑动态属性、用 class:list 拼 class、用 set:html 插原始 HTML。它们都跑在“服务器算好再发 HTML”的节奏里,所以写起来直观、出 Bug 也少。下一章讲怎么把数据从外面“传进”组件——也就是组件的 Props 与 TypeScript 类型。