838 字
4 分钟
Svelte 5 在博客里到底负责什么

静态博客也需要一点交互:搜索框、标签筛选、主题切换、折叠面板。关键在于——不要因为一点点交互,就让整个页面都变成客户端应用。

Svelte 5 在这个项目里的角色,是「局部增强」,而不是「接管页面」。

先静态,再交互#

大部分文章页、归档页、关于页都是纯 Astro 组件,构建时直接输出 HTML。只有真正需要响应点击和输入的部分,才会写成 Svelte 组件,并通过 hydration 指令挂载。

立即加载

适合首屏就需要立即可用的组件,例如导航栏里的搜索入口。对应的指令是 client:load,代价是脚本会在页面加载后马上执行。

滚动到附近再加载

适合首屏之外、滚动到附近才需要工作的组件。对应的指令是 client:visible,文章底部的相关推荐、相册列表都可以用这个策略。

仅客户端

完全跳过服务端渲染。对应的指令是 client:only,只适合依赖浏览器 API、无法在构建时渲染的组件。

这三种策略的区别,本质上是在回答一个问题:这个交互最早什么时候可能被用到?

Runes 让状态更直白#

Svelte 5 的 runes 写法比过去的响应式语法更接近普通 JavaScript:

一个简单的筛选状态
<script lang="ts">
let query = $state("");
let selectedTag = $state("");
let filtered = $derived(
items.filter((item) => item.title.includes(query))
);
</script>
<input bind:value={query} />

$state 声明可变状态,$derived 声明派生值。比起手动维护依赖关系,这种写法更容易读,也更不容易漏掉更新。

一个真实的取舍#

筛选器需要读取 URL 参数,让刷新和分享后的状态保持一致。这段逻辑只能在浏览器里运行,所以放在 onMount 中;但它又不需要整个页面都变成客户端组件。

交互的边界应该由需求决定,而不是由框架决定。

我把筛选器拆成独立组件,只让它自己承担状态,页面其余部分继续静态输出。这样一来:

  • 没有筛选需求的读者,不会为这段脚本付出首屏成本;
  • 需要交互的读者,点开筛选器后功能完整可用;
  • 构建时仍然能生成可读的 HTML,搜索引擎和 RSS 不受影响。
那动画呢?

筛选切换时的淡入和加载指示器也用 Svelte 状态驱动,但动画本身遵循系统的 prefers-reduced-motion 设置。交互可以有趣,但不应该强迫所有人接受。

小结#

Svelte 5 在这个博客里不是主角,而是配角。它负责把少数需要响应的地方做得顺滑,其余部分交给 Astro 在构建时完成。这种分工听起来保守,但对内容站来说,保守往往意味着更快的首屏和更少的故障面。

第 2 篇,共 12 篇本文属于系列

Svelte 5 在博客里到底负责什么
https://www.ycera.cn/posts/svelte-5-in-blog/
作者
初月_Yuechu
发布于
2026-10-21
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取