Svelte 5 与编译时响应式

共 18 题
📑 题目列表 18 题
#
★★★

1. Svelte 5 的 Runes($state/$derived/$effect)与旧版 $: 语法的差异与迁移要点?

Svelte 5 的 runes($state/$derived/$effect)与旧版 $: 响应式语法有何差异?迁移时有哪些要点?

  • 旧版基于变量赋值静态分析的隐式响应式与其限制
  • runes 显式声明的形态与模块级可用性
  • 迁移工具、混用边界与逐组件转换策略

旧版 Svelte 的响应式基于编译器对变量赋值的静态分析:声明 let 变量即为响应式,$: 声明派生语句。这种隐式机制的限制在于:无法在运行时动态创建响应式变量、不能在 .js/.ts 模块文件中使用、在循环、闭包与复杂控制流中容易失效,且依赖编译器对"赋值位置"的识别,语义不够直白。runes 模式把响应式声明显式化:let count = $state(0) 声明响应式状态,let doubled = $derived(count * 2) 声明派生值,$effect(() => {...}) 声明副作用,并可在任何 .svelte.js/.svelte.ts 模块中使用,运行时也能动态创建,语义清晰且可静态分析。

迁移要点:let count = 0 改为 let count = $state(0);$: doubled = count * 2 改为 $derived;$: 内包含副作用的语句改为 $effect;事件中赋值与模板引用基本不变。官方提供迁移工具可自动转换大部分旧语法,组件可以逐文件迁移,legacy 模式与 runes 模式在单个组件内可以混用,但新代码应统一 runes 风格;迁移后用类型检查与测试回归兜底。

本题考察 Svelte 响应式机制的核心演进:从"编译器猜测你的意图"到"开发者显式声明"(隐式到显式)。回答要点是旧语法局限、runes 三原语语义与可操作的迁移路径。

<script>
  let count = $state(0);
  let doubled = $derived(count * 2);
  $effect(() => console.log(doubled));
</script>
<button onclick={() => count++}>{doubled}</button>
#
★★★

2. Svelte 的编译时特性如何实现"无运行时"优势,代价是什么?

Svelte 的编译时特性如何实现"无运行时"优势?这种设计付出的代价是什么?

  • 编译器把模板编译为直接操作 DOM 的更新代码
  • 极小运行时辅助与无虚拟 DOM 的收益
  • 代价:工具链依赖、调试体验、重编译时间

Svelte 编译器在构建期分析模板表达式与赋值语句,把组件编译为直接操作 DOM 的代码:对每个被读取的变量生成精确的 DOM 更新指令(如 text 节点的 setData、属性/class 的更新),运行时只需极小的一组辅助函数,不需要虚拟 DOM 与运行时解释器,也不需要组件级的重渲染机制。收益体现在产物体积小、解析快、启动快,以及更新精确(更新成本与"被赋值的变量"成正比,与组件规模无关)。

代价:模板语法是编译器专用语言,IDE 支持、代码高亮、第三方工具(如部分插件)依赖编译器的配合;编译生成的代码与源码差异较大,调试时依赖 sourcemap 定位;大型项目的重编译耗时高于纯运行时框架;HMR 与 dev 体验依赖编译管线质量;生态中"运行时插件式"的扩展(如动态模板)受限。此外,编译时优化要求模板可静态分析,过于动态的写法会失去部分优化收益。

本题考察"编译时优化"的收益与代价两面性。回答要说明编译产物形态(赋值→DOM 更新指令)带来的体积与性能优势,同时诚实指出工具链、调试与编译成本的代价,避免单边化表述。

#
★★★

3. Svelte 5 的七大核心 runes($state/$derived/$effect/$props/$bindable/$mutable/$host)各自的职责?

Svelte 5 的七大核心 runes——$state、$derived、$effect、$props、$bindable、$mutable、$host——各自的职责是什么?

  • 状态、派生、副作用三原语($state/$derived/$effect)
  • 组件边界($props/$bindable)
  • 高级场景($mutable/$host)的用途

七大 runes 覆盖响应式状态与组件边界的完整场景:$state 声明响应式状态,对对象/数组等默认进行深层代理,赋值即触发更新;$derived 声明依赖派生的只读值,惰性求值并缓存;$effect 声明副作用,自动跟踪其读取的响应式值并在变化时重新执行(可注册清理函数);$props 声明组件入参,解构出的属性保持响应式并可设默认值;$bindable 使 $props 中的属性支持父级双向绑定(相当于可写 props);$mutable 声明"可变引用"状态,不做深层代理,适合大对象、class 实例等不希望被深度追踪的场景;$host 在自定义元素场景中访问宿主元素,用于透传属性与事件。

使用要点:$state 与 $derived 是纯数据层,$effect 承担副作用(DOM 操作、日志、订阅)并配合清理函数;$props/$bindable 定义组件契约;$mutable 与 $state.raw 类似提供"跳过深层代理"的逃逸口;$host 主要用于 custom element 集成。七个 rune 分工明确,回答时按"状态/派生/副作用"与"组件边界/宿主互操作"两条线组织最清晰。

本题考察 runes 体系的完整语义地图。回答应逐个说明职责并归类:三原语管响应式数据、两个管组件边界、两个管高级场景,能体现对 runes 设计的整体把握。

#
★★

4. SvelteKit 的路由、服务端加载与表单操作(form actions)设计?

SvelteKit 的路由、服务端加载(load)与表单操作(form actions)是如何设计的?

  • 文件系统路由与 +page.server.ts/+page.ts 的 load 职责
  • load 数据的序列化注入与客户端/服务端分工
  • form actions 与 use:enhance 的渐进增强

SvelteKit 采用文件系统路由:+page.svelte 定义页面、+layout.svelte 定义布局、+page.server.ts 的 load 在服务端执行(可访问数据库、密钥等私密资源),返回数据序列化后注入页面,+page.ts 的 load 在客户端执行(仅浏览器环境);+server.ts 导出 GET/POST 等处理函数提供 API 端点。load 支持缓存、依赖管理与错误/重定向(throw redirect/error),SSR 时数据在服务端获取,客户端导航时可通过 fetch 复用或重新执行。

form actions:在 +page.server.ts 中 export const actions 定义服务端动作(default、login 等命名动作),页面

在无 JS 时由浏览器原生提交,启用 use:enhance 指令后升级为 fetch 提交并自动处理 ActionResult(成功/失败、表单数据回填),实现"一套表单两套执行路径"的渐进增强。actions 内通过 request.formData() 取值,返回结构数据供页面显示错误与状态。

本题考察 SvelteKit 的核心数据流设计。回答要点:文件路由 + load 双端执行、actions 的渐进增强(无 JS 原生、有 JS 增强)、错误处理贯穿,体现对全栈框架数据流的系统理解。

#
★★

5. Svelte 的 store 体系与 runes 的对比,全局状态如何组织?

Svelte 的 store 体系与 runes 相比有何异同?全局状态应如何组织?

  • writable/readable/derived store 与 $ 前缀自动订阅
  • runes 在模块级声明全局信号的能力
  • store 与 runes 的共存策略与全局状态组织原则

store 是 Svelte 4 时代的全局状态方案:writable() 创建可写存储、readable() 创建只读存储、derived() 派生新 store,组件模板中 $store 语法自动完成订阅与退订;store 定义在 .js 模块中,模块级单例天然实现跨组件共享。runes 模式用 $state 在 .svelte.js/.svelte.ts 模块作用域声明全局信号,实现等价能力,且读取即追踪、无需订阅语法,语义更直接;官方推荐新代码使用 runes,store 保留用于既有代码与第三方库兼容(旧组件仍可用 $ 前缀订阅 store)。

全局状态组织原则:模块级单例适合"应用级共享"(用户信息、配置),但全局单例在测试与 SSR 场景易互相污染,因此跨组件共享优先用 context(setContext/getContext)限定作用域;共享逻辑抽成"创建状态"的工厂函数便于按需实例化。判断标准:状态是"全局唯一"还是"作用域共享"决定用模块信号还是 context。

本题考察 store 与 runes 的能力对比与组织方法论。回答要点:store 的订阅模型 vs runes 的声明式信号、模块级共享的实现、context 作用域隔离与测试/SSR 考量。

#
★★

6. runes 如何在 .svelte.js/.svelte.ts 中实现跨组件响应式逻辑复用(store 替代)?

runes 如何在 .svelte.js/.svelte.ts 模块中实现跨组件响应式逻辑复用?如何替代 store?

  • 模块级 $state 信号与全局共享
  • 工厂函数导出实现独立实例复用
  • SSR 场景下模块级状态的隔离处理

runes 模式允许在任何 .svelte.js/.svelte.ts 模块中使用 $state、$derived、$effect,因此"响应式逻辑"可以完全脱离组件文件组织:模块顶部用 $state 声明的信号是模块级单例,所有引用它的组件共享同一状态,等价于模块级 store 单例;更灵活的复用方式是导出"创建函数"(工厂):函数内部用 $state 创建状态并返回带操作方法的对象,调用方各自实例化,实现"多实例、可组合"的响应式逻辑复用,替代以前用 store 工厂(writable() 返回实例)的写法。

与 store 的差异:runes 读取即追踪,无需 $ 订阅语法,逻辑可以跨 .svelte.js 模块自由组织;$derived 替代 derived store,$effect 替代订阅副作用。需要注意 SSR:模块级信号是跨请求共享的,服务端渲染时不同请求会互相污染,应在服务端按请求重建(如通过 request 作用域的 context 创建实例),客户端则用模块级单例即可。

本题考察 runes 的模块化复用能力。回答要点:模块级信号=全局单例、工厂函数=独立实例、SSR 隔离是工程关键,体现从"store 心智"到"信号心智"的迁移。

#
★★

7. Svelte 5 的渐进迁移,legacy 模式与 runes 模式共存时的边界?

Svelte 5 的渐进迁移中,legacy 模式与 runes 模式共存时有哪些边界?

  • 编译器 runes/legacy 选项与组件内混用规则
  • $: 与 runes 在同一组件中的语义边界
  • store 订阅与 runes 状态的互操作

Svelte 5 默认使用 runes 模式,legacy 模式通过编译器选项(compilerOptions.runes: false 或组件顶部 runes 指令)启用旧语法,目的是让存量项目按组件逐个迁移。同一组件内允许混用:$: 语句与 $state/$derived/$effect 可以并存,旧语法引用 rune 声明的状态仍保持响应式;但需注意边界语义——$: 的依赖分析基于赋值追踪,而 rune 状态是显式信号,混写时派生链要避免两种机制的隐式交错导致意外不更新;store 的 $ 前缀订阅与 runes 状态声明互不冲突,旧组件可以继续订阅 store,新组件用 $state 读取。

实践边界:迁移按组件推进(先叶子、后容器),同一组件内过渡期可混用但不鼓励长期混写;runes 模式文件中的 $: 仍可用(兼容保留),但新代码应统一 runes;使用官方迁移工具处理机械转换($: 派生→$derived、赋值→$state 初始化),复杂副作用手工审查,最后以类型检查与测试回归确认语义未变。

本题考察渐进迁移的兼容机制。回答要点是"共存允许但语义边界要清晰":混用可行、store 可互操作、迁移按组件推进并用工具+测试兜底。

#
★★

8. Svelte 5 的 snippets(#snippet 与 @render)替代 slot 的模板复用与类型安全,以及 children 属性传递的边界?

Svelte 5 的 snippets(#snippet 与 @render)如何替代 slot 实现模板复用与类型安全?children 属性传递的边界是什么?

  • {#snippet} 定义与 {@render} 调用的语法与传参
  • snippet 参数的 TypeScript 类型化
  • children 默认内容与命名 snippet 的接收与边界

snippets 是 Svelte 5 的模板复用机制:用 {#snippet name(args)} 定义可复用的模板片段,用 {@render name(args)} 在需要处渲染,支持传参、条件渲染与循环复用,解决了旧 slot 不能向父级传参、作用域割裂的问题。类型安全方面,snippet 可以像函数一样标注参数类型({@render header(item: Item)}),配合 TypeScript 实现模板级静态检查,避免 slot 时代"属性类型全靠运行时"的脆弱性。

children 传递边界:组件通过 {#snippet children()} 接收默认插槽内容,命名 snippet(如 {#snippet footer()})通过 $props 接收;snippet 的定义作用域在定义处(父组件模板),子组件只能渲染不能重定义其内部细节;snippet 也可作为 props 传给其他组件实现渲染注入。边界注意:snippet 不能跨组件文件定义,水合(SSR)时 snippet 的渲染与更新按依赖粒度追踪,动态切换 {@render} 目标会触发对应区域更新。

本题考察 snippets 对 slot 的替代关系。回答要点:可传参、类型化、children 默认内容与命名 snippet 的接收方式、作用域边界,突出类型安全这一核心优势。

#
★★

9. Svelte 编译器的依赖收集机制,编译期如何分析变量赋值与读取生成更新代码,与脏检查/订阅相比的收益?

Svelte 编译器的依赖收集机制是如何工作的?与脏检查、订阅模式相比收益在哪里?

  • 编译期对模板读取与赋值语句的分析
  • 为赋值生成精确 DOM 更新代码的机制
  • 与脏检查(全量比对)、订阅(运行时注册)的对比收益

Svelte 编译器在构建期对组件做静态分析:扫描模板中每个表达式读取了哪些变量,扫描脚本中每个赋值语句的目标变量,然后把两者关联——为每条赋值语句生成对应的 DOM 更新代码(该变量参与渲染的 text/attribute/class 节点更新指令),运行时执行赋值时直接调用这些生成函数,实现"变量 → DOM"的精确映射。这种机制下更新代码在编译期确定,运行时没有依赖注册表、没有订阅分发,也没有 diff 过程。

与脏检查对比:脏检查(如早期 Angular)每轮要遍历组件树比对数据是否变化,Svelte 只在赋值发生时才更新相关节点,省去全量比对;与订阅模式对比:订阅式响应式(如 Vue 依赖收集)在运行时维护依赖关系与通知队列,Svelte 把这一层前置到编译期,运行时开销趋近于零。收益在更新频繁、列表巨大的场景最明显:更新代价与"被赋值的变量"数量相关,与组件规模无关。

本题考察编译时响应式的核心机制。回答要讲清"读取分析 + 赋值插桩"的编译产物,并与脏检查、订阅两种运行时方案对比,突出"把优化前置到构建期"的本质。

#
★★

10. Svelte 5 与 React/Vue 响应式实现的本质差异,编译期信号 vs 运行时 proxy,调试体验与性能剖面如何对比?

Svelte 5 与 React、Vue 的响应式实现本质差异是什么?编译期信号 vs 运行时 proxy 在调试体验与性能剖面上如何对比?

  • Svelte 编译期信号 vs Vue 运行时 Proxy 依赖追踪 vs React 不可变加重渲染
  • 调试体验:DevTools 生态与 sourcemap 依赖
  • 性能剖面:更新粒度、代理成本与包体

三类方案的响应式路线完全不同:Vue 在运行时用 Proxy 包装响应式对象,读取时收集依赖、写入时触发更新,机制灵活(运行时动态添加属性也响应式),但深层代理与数组/Map 操作有运行时成本;React 依赖不可变更新 + 从根组件重新执行组件函数(配合 memo/useMemo 剪枝),以重渲染换取简单的心智模型;Svelte 5 在编译期把 runes 降级为内部信号调用,赋值即触发精确更新,无代理、无虚拟 DOM、无组件重渲染,运行时最小。

调试体验:React DevTools(组件树、profiler)与 Vue DevTools(依赖图、时间线)生态成熟,可直观查看组件与依赖;Svelte 需要依赖官方 devtools(组件检查)与 sourcemap 定位生成代码,栈信息与源码映射依赖工具质量,社区工具链仍在完善。性能剖面:Svelte 更新粒度细(表达式级)、启动快、包体小;Vue 的代理在嵌套深层对象与大量数组操作场景有额外开销;React 在大型树的高频更新下 diff 与重渲染成本较高。结论:性能敏感与资源受限场景 Svelte 占优,调试工具与生态 React/Vue 更成熟。

本题考察三大框架响应式路线的横向对比。回答按"实现机制—调试体验—性能剖面"三条线展开,给出各自的取舍结论,避免简单断言谁优谁劣。

#
★★

11. Svelte 5 的 hydration 与岛屿架构,服务端渲染组件与客户端交互组件如何分层,与 Next.js/Remix 的形态差异?

Svelte 5 的 hydration 与岛屿架构中,服务端渲染组件与客户端交互组件如何分层?与 Next.js/Remix 的形态差异是什么?

  • SvelteKit 默认全量水合与 Svelte 5 的细粒度水合选项
  • 岛屿化(islands)的分层方式
  • 与 Next.js 服务端组件、"use client"、Remix 数据流的形态对比

SvelteKit 默认 SSR 全量水合:服务端渲染整页 HTML,客户端对整棵组件树水合以恢复交互;Svelte 5 提供更细的水合控制(hydration: 'event'/'effects' 等选项,按需激活交互能力),并支持在 SvelteKit 中配置 islands 形态——只有标注交互的组件被水合,静态区域零 JS。分层原则:静态内容(文章、样式、展示)走服务端输出,交互组件(表单、控件、实时区域)作为岛屿单独加载,岛屿间通过事件或共享状态通信。

与 Next.js 的差异:Next.js 用文件级"use client"声明客户端边界,服务端组件与客户端组件混编,水合粒度组件级、运行时与路由深度集成;SvelteKit 默认整页水合、可按需岛屿化,水合粒度更细但需要显式配置。与 Remix 的差异:Remix 强调 loaders/actions 与"少客户端状态"的渐进增强(表单提交、数据重验证),客户端交互依赖增强指令;SvelteKit 以编译时响应式 + 细粒度更新见长,同样内置数据加载与表单动作,但响应式机制是编译期信号而非重渲染。

本题考察 SSR 形态的横向对比。回答要点是"水合粒度"与"边界声明方式"两个维度:SvelteKit 默认全量、可岛屿化;Next.js 文件级边界;Remix 数据流优先。

#

12. Svelte 编译产物(无虚拟 DOM)与信号式运行时的性能差异在什么场景可感知?

Svelte 编译产物(无虚拟 DOM)与信号式运行时的性能差异在什么场景下可感知?

  • 首屏体积与启动解析差异
  • 高频列表更新与交互密集场景
  • 低交互场景下差异不明显的边界

可感知的典型场景:移动端与弱网环境——Svelte 产物体积小、解析执行快,首屏与启动差异明显;高频更新的列表与仪表盘——精确 DOM 更新(仅更新变化节点)优于虚拟 DOM 的 diff 与重建;交互密集的小部件(拖拽、画布控件、实时输入)——没有 diff 开销且更新按表达式粒度,交互延迟更低;内存受限的设备——无虚拟 DOM 树,内存占用更小。

差异不明显的场景:低交互的内容页(博客、文档)、更新频率低的大型静态树——diff 成本被摊薄,此时首屏体积与开发者体验更值得关注。与信号式运行时(如 Solid)对比,两者性能剖面接近,主要差异在编译产物体积与运行时辅助量,js-framework-benchmark 显示两者在创建/更新/清除列表等指标上均显著优于虚拟 DOM 方案,实际差距需结合真实业务页面验证。

本题考察性能差异的"适用边界"。回答要点是场景化判断:更新频率高 + 资源受限时收益可感知,低交互场景不敏感,并与信号式方案做同类对比。

#

13. 编译时响应式 vs 运行时响应式,性能与调试差异?

编译时响应式与运行时响应式在性能与调试上有哪些差异?

  • 编译期静态分析的收益(运行时零开销)与限制(动态场景受限)
  • 运行时 Proxy/订阅的灵活性与成本
  • 调试工具与堆栈体验差异

编译时响应式(Svelte)在构建期确定依赖与更新代码:运行时只执行生成的精简指令,无依赖注册、无代理包装、无 diff,性能开销低且可摇树;限制是依赖必须可静态分析,运行时动态创建依赖、跨模块动态响应式的表达受限,模板语言与编译器强绑定。运行时响应式(Vue 的 Proxy、Solid 的信号运行时)在运行时追踪依赖:可动态创建与替换响应式对象、跨模块自由组合,灵活性高;代价是每次读写经过代理/订阅层,深层对象、数组操作与大量依赖场景有额外开销。

调试差异:运行时方案有成熟的 DevTools(Vue DevTools 的组件与依赖图、React DevTools),可运行时检查数据与更新链路;编译时方案依赖 sourcemap 把生成代码映射回源码,栈帧与生成代码交织,工具链(官方 devtools 与 IDE 插件)成熟度仍在追赶;编译错误与类型错误在构建期暴露,运行时错误定位需要 sourcemap 配合。选型上:性能敏感、模板受控选编译时;动态灵活、工具链优先选运行时。

本题考察两类响应式路线的取舍。回答用"静态收益 vs 动态灵活"与"构建期暴露 vs 运行时工具"两组对比展开,给出清晰的场景化结论。

#

14. Svelte 5 的组件事件与 props,新旧 API 对比?

Svelte 5 的组件事件与 props 相比旧版 API 有何变化?

  • 旧版 export let 与 createEventDispatcher 的写法
  • 新版 $props 解构与回调 props 的传递方式
  • $bindable 双向绑定与事件转发边界

旧版 API:组件用 export let 声明 props(编译器将其标记为响应式入参),子组件通过 createEventDispatcher 创建 dispatcher 派发事件,父组件用 on:event 监听;事件名与数据经运行时分发,类型推断弱。新版 API:$props() 解构声明全部入参,可设默认值、用 rest 收集剩余属性;事件改为"回调 props"——父组件直接传函数(如 onclick={handle}),子组件调用该函数即可,类型天然显式,无需事件名注册表;$bindable 把某个 props 标记为可写,支持父级双向绑定(等价旧版 bind: 语义)。

对比要点:回调 props 使"事件即入参",接口更显式、类型安全、便于跨框架互操作(自定义元素与框架外调用);旧版 createEventDispatcher 仍兼容保留,但新代码推荐回调 props;属性透传(rest props 转发到 DOM 元素)在新旧版本中都是常用模式,新版通过 $props 的 rest 收集更统一。注意边界:回调 props 是单向数据流的一部分,需要双向时用 $bindable,避免把整个父组件对象作为 props 传递造成耦合。

本题考察组件通信 API 的演进。回答要点是"事件总线 → 回调即 props"的显式化趋势,以及 $bindable 对双向绑定的承接,突出类型安全与互操作优势。

#

15. Svelte 5 的过渡与动画,内置指令?

Svelte 5 的过渡与动画内置指令有哪些?如何使用?

  • transition:/in:/out: 指令与内置动画函数
  • flip 列表移动动画
  • 参数、deferred 协调与性能注意

Svelte 提供三个过渡指令:transition:fn 同时处理进入与离开,in:fn 只处理进入,out:fn 只处理离开;内置动画函数有 fade、fly、slide、scale、blur、draw 等,可传参(duration、delay、easing、自定义参数),也可编写自定义过渡函数(返回 start/end 的 transition 函数)。列表场景用 flip:fn 指令,元素位置变化时自动动画到新位置;结合 keyed each 块({#each items as item (item.id)}),列表增删移动都能得到平滑动画。

进阶用法:out 过渡会延迟元素真正移除,配合 keyed each 保证动画完整;多个元素联动可用 deferred 过渡协调入场顺序;过渡基于 Web Animations API 与 requestAnimationFrame 编译进更新逻辑,无需额外动画库。性能注意:避免对超大列表全量加过渡,动画元素过多时用 will-change 与减少同时动画数量控制合成器压力,尊重 prefers-reduced-motion 提供关闭选项。

本题考察 Svelte 动画指令的用法全貌。回答要点:transition/in/out/flip 指令、内置函数与参数、列表动画与性能注意,体现"编译器原生支持动画"的特色。

#

16. Svelte 5 的 SSR 与 islands?

Svelte 5 的 SSR 与 islands 架构是怎样的?

  • SSR 渲染流程与数据注入
  • 部分水合(islands)的粒度与控制
  • SvelteKit 中启用 islands 的方式与代价

SvelteKit 在服务端执行 load 与组件渲染输出完整 HTML,数据通过序列化注入客户端(默认 data-sveltekit-fetched 机制或流式传输),客户端复用服务端 DOM 进行水合。Svelte 5 增加细粒度水合选项(hydration: 'event'、'effects'、'visible' 等),允许只激活部分交互能力,减少水合工作量与客户端 JS;在此基础上 SvelteKit 支持 islands 形态:默认把组件渲染为静态 HTML,仅对标注交互的组件加载运行时并水合,实现"内容零 JS、交互按需激活"。

启用 islands 的方式:在 SvelteKit 配置中开启 islands 模式并标注交互组件边界(如 island 指令或组件级配置),静态区域不加载框架运行时。收益是更快的 TTI 与更小的客户端包体;代价是岛屿间的状态共享与事件冒泡需要跨边界处理(通过事件、全局状态或上下文传递),动态区域需要显式设计边界,调试与依赖图管理复杂度上升。

本题考察 Svelte 5 SSR 与岛屿化的能力与权衡。回答要点:SSR 数据流、细粒度水合选项、islands 的启用方式与跨岛屿协作的代价。

#

17. Svelte 5 的 $state 代理语义,数组/Map/class 的深层响应式与 .raw 跳过代理的取舍?

Svelte 5 的 $state 代理语义如何实现数组、Map、class 实例的深层响应式?何时用 $state.raw 跳过代理?

  • $state 对对象/数组/Map/Set 的深层代理与操作追踪
  • class 实例的代理边界
  • $state.raw 跳过深层代理的适用场景

$state() 默认对传入的值创建深层代理:对象属性读写、数组的 push/splice/索引赋值、Map 的 set/delete、Set 的 add 等方法调用都会被追踪并触发更新,因此可以直接使用原生可变 API 而保持响应式。class 实例的代理是浅层的(实例属性直接代理,但构造函数内部初始化的私有字段与方法内的赋值追踪有边界),复杂 class 场景建议用 $state.raw 或显式整体替换。

$state.raw 创建"不做深层代理"的状态:读取与整体赋值仍响应式,但内部结构变化(如修改对象的子字段、调用数组方法)不会被追踪,适合大对象、频繁整体替换的状态、第三方库管理的实例等场景,可避免代理开销与意外追踪(如性能敏感的大数据对象、需要保持对象身份的场景)。取舍原则:需要细粒度内部可变操作用默认 $state;结构整体替换、内部由外部管理或性能敏感时用 $state.raw;两者可以在同一组件中按需混用。

本题考察 $state 的代理语义细节。回答要点是深层代理覆盖的容器类型与操作、class 与代理的边界、.raw 的逃逸场景,体现对响应式实现层级的理解。

<script>
  let list = $state([1, 2, 3]);
  list.push(4); // 数组方法调用被追踪
  let meta = $state.raw({ size: 1000 }); // 跳过深层代理
</script>
#

18. Svelte 的过渡动画与微交互实现相比 React/Vue 的优势?

Svelte 的过渡动画与微交互实现相比 React/Vue 有哪些优势?

  • 编译期生成动画代码与更新逻辑的协同
  • 内置过渡/flip 指令与 keyed each 的动画编排
  • 无需额外动画库的体验优势与生态局限

Svelte 把过渡与动画作为一等语法编译进更新逻辑:transition/in/out 指令在元素进入/移除时自动触发动画,flip 指令处理列表移动,keyed each 与 out 动画配合实现"先动画后移除"的正确时序,所有动画与响应式更新天然协同,无需手写 CSS 类切换或状态编排。React/Vue 通常需要额外动画库(framer-motion、vue transition 组件 + CSS)或手工管理 enter/exit 状态与定时器,微交互的时序编排(进入/退出/交错)代码更繁琐。

优势具体表现为:声明式、代码量少、动画与数据更新一致(元素移动/增删自动衔接),且无需为动画引入额外运行时依赖;劣势是复杂编排(拖拽、手势、物理动画)仍需要手写或第三方库支持,动画生态(可复用动画组件、预设)不如 React 生态丰富。选型上,常规 UI 微交互 Svelte 体验最好,重交互动画场景需评估生态。

本题考察 Svelte 动画能力的差异化优势。回答要点是"编译器原生支持 + 与更新逻辑协同 + 无需依赖",同时诚实指出复杂动画场景的生态局限。