Svelte 精要与 Vue 对照
用 Vue 的知识体系理解 Svelte:编译时框架、runes 响应式与 Vue 组合式 API 的一一对应。
0. 一句话理解
Svelte 与 Vue 同属”模板 + 响应式”流派:Vue 在运行时用响应式代理加虚拟 DOM 追踪依赖,Svelte 在编译期把组件直接编译成操作 DOM 的原生 JavaScript,没有虚拟 DOM。
1. Svelte 是什么
Svelte 是一个”编译时框架”:React 与 Vue 在浏览器里做运行时 diff,Svelte 则在构建阶段完成依赖分析与更新代码生成,运行时体积小、更新路径短。
Svelte 5(2024-10 发布)引入 runes(符文)语法,用 $state、$derived、$effect 显式声明响应式,替代旧版 let 自动响应式与 store 体系。当前稳定版为 Svelte 5.55.x 与 SvelteKit 2.57.x(2026-05),新项目统一使用 SvelteKit 脚手架。
2. 五分钟跑起来
npx sv create my-app
cd my-app
npm run dev
sv create是官方 CLI,选择 SvelteKit 模板;开发服务器默认http://localhost:5173。- 页面文件是
src/routes/+page.svelte,文件即路由,改完保存即热更新。
3. 组件文件对照
Svelte 的 .svelte 文件与 Vue 单文件组件结构同构:<script> 对应 <script setup>,模板直接写 HTML,样式写在 <style>。
<!-- src/routes/+page.svelte -->
<script>
let count = $state(0)
function add() {
count += 1
}
</script>
<main>
<h1>你好,Svelte 5</h1>
<p>点击次数:{count}</p>
<button onclick={add}>加一</button>
</main>
{count}插值等价于 Vue 的{{ count }}。- 事件绑定用属性形式
onclick={add}(注意是全小写onclick,不是onClick),等价于 Vue 的@click="add"。 - 编译后没有虚拟 DOM:按钮点击直接更新那一个
<p>的文本节点。
4. 响应式对照:runes 对组合式 API
Svelte 5 的三个符文与 Vue 组合式 API 几乎一一对应:
| Svelte 5 | Vue 3 | 差异要点 |
|---|---|---|
let count = $state(0) | const count = ref(0) | Svelte 直接赋值 count += 1 触发更新;Vue 需要 .value |
let total = $derived(price * qty) | const total = computed(() => ...) | 都是只读派生值,依赖变化自动重算 |
$effect(() => { ... }) | watchEffect(() => { ... }) | 都自动追踪函数内读取的响应式值,返回清理函数做取消订阅 |
<script>
let price = $state(100)
let qty = $state(2)
let total = $derived(price * qty)
// 副作用:keyword 变化时自动重新执行,类似 watchEffect
let keyword = $state("")
$effect(() => {
console.log(`搜索关键词:${keyword}`)
})
</script>
要点:
$derived只读,不要手动赋值,它保证显示值与源数据一致——语义与computed相同。$effect用于日志、同步localStorage、对接非响应式 API;不要在里面反向修改其他响应式变量,否则循环触发,这与watchEffect的使用纪律一致。- 旧版 store(
writable与模板$count自动订阅)仍兼容,存量项目无需迁移;新项目跨组件共享状态用模块级$state导出即可。
5. 组件通信与插槽对照
<!-- Svelte 5 子组件:callback props 替代事件 -->
<script>
let { count = $bindable(0), onchange } = $props()
</script>
<button onclick={() => onchange(count + 1)}>{count}</button>
<!-- Vue 子组件:emits 声明事件 -->
<script setup>
defineProps(['count']);
const emit = defineEmits(['change']);
</script>
<template>
<button @click="emit('change', count + 1)">{{ count }}</button>
</template>
- Svelte 5 用普通函数属性
onchange={...}回传,Vue 用emit+@change——名字都是约定,本质都是”父组件把回调传下去”。 - 双向绑定:Svelte 的
$bindable+bind:count对应 Vue 的defineModel+v-model:count,同样是”属性下行、事件上行”的语法糖。 - 内容分发:Vue 的
<slot>(含具名插槽与作用域插槽)对应 Svelte 5 的{@render children()}与 snippet 参数,都是”父组件传模板、子组件决定渲染位置”。
6. 双向绑定:bind: 对 v-model
<script>
let name = $state("")
let agree = $state(false)
</script>
<input bind:value={name} placeholder="姓名" />
<input type="checkbox" bind:checked={agree} />
bind:value让输入框与变量双向同步,等价于 Vue 的v-model;复选框用bind:checked,对应v-model在复选框上的行为。- 相比 React 受控组件(
value加onChange)的写法,Svelte 与 Vue 的双向绑定都是语法糖,底层仍是”属性下行、事件上行”。
7. 路由与全栈:SvelteKit 对 Vue Router 与 Nuxt
| 能力 | Svelte 生态 | Vue 生态 |
|---|---|---|
| 组件级路由 | SvelteKit 文件路由(+page.svelte 即路由) | Vue Router(vue3/190-VueRouterDetailed) |
| 数据加载 | +page.ts 的 load 函数 | 路由守卫与组合函数 |
| 全栈元框架 | SvelteKit | Nuxt |
两者思路一致:文件约定代替路由配置,服务端与客户端共享同一套路由定义。差异在生态位:Nuxt 背靠 Vue 官方周边(Router、Pinia、DevTools)与更大的组件库生态,SvelteKit 则更轻、约定更少。
8. 编译时思想的趋同:Svelte 对 Vue 3.6 Vapor
Svelte 最独特的卖点是”没有虚拟 DOM”,而 Vue 3.6 的 Vapor 模式正是向同一方向的靠拢:
| 维度 | Svelte(一贯如此) | Vue 3.6 Vapor(RC) |
|---|---|---|
| 更新方式 | 编译期生成定向 DOM 操作 | 编译期生成定向 DOM 操作 |
| 响应式来源 | 编译期信号(runes) | 运行时响应式代理(ref/reactive) |
| 组件 API | 独有语法($state 等) | 与虚拟 DOM 模式完全一致 |
| 迁移成本 | 换框架 | 同一框架内渐进启用 |
结论:Vapor 落地后,“是否编译时”不再构成选型分界,分界回到生态体量、团队经验与全栈框架成熟度。这也解释了为什么本文强调的响应式心智(ref/computed/watchEffect)在 Vapor 时代依然完全适用。
9. 选型建议
- 团队已有 Vue 技术栈、需要丰富生态(组件库、后台模板)时,继续用 Vue;Svelte 生态体量更小。
- 追求极致包体积与首屏性能(嵌入式 WebView、营销页、小组件)时,Svelte 的编译时方案值得评估。
- 从 Vue 迁移 Svelte 的心智成本很低:模板语法、响应式划分、单向数据流全部同构,主要差异只是”编译期完成依赖追踪”这一条。
10. 动手试试
- 用
sv create建一个计数器,把vue3/020-Vue3QuickStartGuide的计数器用 runes 重写一遍,对比两者代码量。 - 给计数器加”减一”按钮,数量为 0 时禁用(
disabled={count <= 1})。 - 用模块级
export const cartCount = $state(0)做跨页面共享状态,再回想 Pinia 解决的是同一个问题。
11. 一句话记住
Svelte 是”编译时”的 Vue:
$state、$derived、$effect对应ref、computed、watchEffect,bind:对应v-model,模板与单向数据流心智完全通用。