浏览器支持与最佳实践
本教程共 50 篇 · 第 41 篇 · 更新于 2026-08-05 · 约 5 分钟阅读
41. 浏览器支持与最佳实践
本节目标:了解 Svelte 5 的浏览器兼容范围,掌握代码组织的最佳实践、性能优化技巧和常见问题。
浏览器兼容性
Svelte 5 依赖一些现代浏览器 API。最低支持版本如下:
| 浏览器 | 最低版本 |
|---|---|
| Chrome | 87+ |
| Firefox | 83+ |
| Safari | 14+ |
| Edge | 87+ |
| iOS Safari | 14+ |
| Android Chrome | 87+ |
这个表格只覆盖 Svelte 本身。SvelteKit 和其他库可能有更高的版本要求。
Note个别 Svelte 特性需要更高的浏览器版本,比如某些过渡动画 API。如果你用了这些特性,需要额外检查兼容性。
$state 最佳实践
只在需要响应式的地方用 $state。不参与响应式更新的普通变量用 let 就行:
// 需要响应式 —— 用 $state
let count = $state(0);
let user = $state({ name: '张三' });
// 不需要响应式 —— 普通 let
let timeoutId = null;
let cache = new Map();
处理大型对象时,如果只整体替换不修改内部属性,用 $state.raw 省去代理开销:
// API 返回的数据通常只整体替换
let data = $state.raw([]);
async function loadData() {
const res = await fetch('/api/data');
data = await res.json(); // 整体替换,不做内部修改
}
$derived 而非 $effect
计算值用 $derived,不要用 $effect 加赋值来模拟(详见 §07 的对比)。$derived 更高效,Svelte 能更好地优化更新。表达式复杂时用 $derived.by。
$effect 使用原则
$effect 是逃生舱口,尽量少用(§08 有详细说明)。优先考虑这些替代方案:
| 需求 | 替代方案 |
|---|---|
| 同步外部库 | {@attach} |
| 响应交互 | 直接写事件处理器 |
| 调试日志 | $inspect |
| 观察外部状态 | createSubscriber |
Warning不要在
$effect里更新状态再被自己监听,这会导致无限循环。如果确实需要”状态联动”,考虑用$derived。
Props 最佳实践
把 props 当作会变化的值。依赖 props 的计算用 $derived:
let { type } = $props();
// 正确 —— type 变了 color 也会更新
let color = $derived(type === 'danger' ? 'red' : 'green');
// 错误 —— type 变了 color 不会更新
let color = type === 'danger' ? 'red' : 'green';
不要修改 props(除非是 $bindable 的)。修改不属于自己组件的状态会导致警告。
事件处理
Svelte 5 中 on 开头的属性就是事件监听器:
<!-- 直接写函数 -->
<button onclick={() => { /* ... */ }}>点击</button>
<!-- 属性简写 -->
<button {onclick}>...</button>
<!-- 展开属性 -->
<button {...props}>...</button>
监听 window 或 document 事件用 <svelte:window> 和 <svelte:document>:
<svelte:window onkeydown={handleKeydown} />
<svelte:document onvisibilitychange={handleVisibility} />
不要用 onMount 或 $effect 来添加事件监听。
Each 块要加 key
遍历列表时加 key 能让 Svelte 精准地增删元素,而不是更新已有元素的 DOM:
<!-- 正确 —— 用唯一 id 做 key -->
{#each items as item (item.id)}
<li>{item.name}</li>
{/each}
<!-- 避免 —— 用 index 做 key 会导致性能问题 -->
{#each items as item, i (i)}
<li>{item.name}</li>
{/each}
Notekey 必须能唯一标识对象。不要用数组索引做 key,列表顺序变化时会导致渲染错乱。
CSS 最佳实践
JS 变量传给 CSS 用 style: 指令设置自定义属性:
<script>
let columns = $state(3);
</script>
<div class="grid" style:--columns={columns}>
<!-- ... -->
</div>
<style>
.grid {
display: grid;
grid-template-columns: repeat(var(--columns), 1fr);
}
</style>
父组件控制子组件样式,优先用 CSS 自定义属性传递:
<!-- Parent.svelte -->
<Child --color="red" />
<!-- Child.svelte -->
<h1>标题</h1>
<style>
h1 {
color: var(--color);
}
</style>
Context 最佳实践
用 Context 而不是全局模块来共享状态。Context 天然限定在组件树范围内,SSR 时不会跨请求泄漏:
// 推荐:用 createContext
export const [getTheme, setTheme] = createContext<Theme>();
Tip
createContext比setContext/getContext类型更安全。Svelte 5.40 起可用。
避免旧写法
新代码统一用 Runes 模式,避免使用已被替代的旧特性。完整的旧写法与新写法对照表见 §42,这里列出几个最常遇到的:
let count = 0→let count = $state(0)on:click={fn}→onclick={fn}<slot>→{@render children()}use:action→{@attach}(Svelte 5.29+)
常见问题
Svelte 能处理大规模应用吗? 能。Svelte 是编译器,运行时极小,性能开销低。许多大型公司在生产环境使用。
有 UI 组件库吗? 有,Svelte 官方网站列了多个组件库和独立组件。
怎么格式化代码? 用 Prettier 配合 prettier-plugin-svelte 插件。
怎么写移动端应用? 把 SvelteKit SPA 用 Tauri 或 Capacitor 包装成移动应用,可访问相机、定位等原生能力。
有路由库吗? 官方路由是 SvelteKit,提供文件路由、SSR 和 HMR。也可以用第三方路由库。
怎么做热更新? SvelteKit 基于 Vite,内置 HMR 支持,不需要额外配置。
本节回顾
- Svelte 5 支持 Chrome 87+、Firefox 83+、Safari 14+ 等现代浏览器
$state只用于需要响应式的变量,大型只替换数据用$state.raw- 计算值用
$derived而非$effect,effect 是最后的手段 - Props 用
$derived派生依赖值,不要直接修改非$bindable的 props - Each 块必须加唯一 key,不要用索引做 key
- 新代码统一用 Runes,避免所有旧写法
- 全局状态优先用 Context 而非模块级变量