svelte 前端框架
官方网站
创建新的项目
npx sv create my-app
cd my-app
npm run dev
脚本隔离
svelte怎么实现脚本隔离的呢
<button onclick={() => count++}> clicks: {count}
## $state.raw
在您不希望对象和数组深度反应式的情况下,您可以使用 `$state.raw`。
```html
<script module>
let person = $state.raw({
name: "Jane",
age: 18,
});
person.age+=1
person = {
name: 'Heraclitus',
age: 50
};
</script>
This reference only captures the initial value of
person. Did you mean to reference it inside a closure instead?
当然会报错 是否在闭包中使用它
$state.snapshot
要对深度响应式的state.snapshot:
<script> let counter = $state({ count: 0 });
function onclick()
{ // Will log `{ count: ... }` rather than `Proxy { ... }` console.log($state.snapshot(counter)); }
</script>
你想将一些状态传递给不期望代理的外部库或 API(例如 structuredClone)时,这会很方便。

返回当前的代理对象 做浅克隆的时候非常有用
$derived 无副作用
理解双向绑定或者计算属性. 替代没有 $:
$derived (...) 内部的表达式应该没有副作用。Svelte 会禁止在派生表达式中进行状态更改(例如 count++)。
<script>
let count = $state(0);
let doubled = $derived(count * 2);
</script>
<button onclick={() => count++}>
{doubled}
</button>
<p>{count} doubled is {doubled}</p>
测试一下?
如果没添加的话 count 的值改 变 doubled 没有任何变化
Svelte 组件中的代码仅在创建时执行一次。如果 没有 $derived符文,即使count发生变化,doubled也将保持其原始值。
$effect
效果使您的应用程序“执行操作”。当 Svelte 运行效果函数时,它会跟踪访问了哪些状态(和派生状态)(除非在 untrack 内部访问),并在该状态稍后更改时重新运行该函数。
Svelte 应用程序中的大多数效果都是由 Svelte 本身创建的——例如,当 name 更改时,它们是更新 <h1>hello {name}!</h1> 中文本的部分。
但是,您还可以使用 $effect 符文创建自己的效果,当您需要将外部系统(无论是库、<canvas> 元素还是网络上的某些内容)与 Svelte 应用程序内的状态同步时,这很有用。
[^]: 避免过度使用 $effect!当您在效果中执行太多工作时,代码通常会变得难以理解和维护。请参阅 何时不使用 $effect 以了解替代方法。
和react 的useeffect 方式差不多,都能修改本身的state 状态change
修改 状态的时候会自动执行函数,无需配置依赖项
<script>
let size = $state(50);
let color = $state("#ff3e00");
let canvas;
$effect(() => {
const context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
console.log("执行了改变ui");
// this will re-run whenever `color` or `size` change
context.fillStyle = color;
context.fillRect(0, 0, size, size);
});
color = "#00";
</script>
<button onclick="{()=>(color = '#ff3e00')}">change</button>
<canvas bind:this={canvas} width="100" height="100" />
$props
组件的输入称为 props,它是 properties 的缩写。您可以像传递属性给元素一样传递 props 给组件
<script>
import MyComponent from './MyComponent.svelte';
</script>
<MyComponent adjective="cool" />
另一方面,在 MyComponent.svelte 内部,我们可以使用 $props 符文接收 props...
<script>
let props = $props();
</script>
<p>this component is {props.adjective}</p>
...尽管更常见的是,您会解构您的 props
<script>
let { adjective } = $props();
</script>
<p>this component is {adjective}</p>
回退值. (默认值 的方式好理解)
解构允许我们声明回退值,如果父组件未设置给定 prop,则使用这些值
let { adjective = 'happy' } = $props();
重命名 props
我们还可以使用解构赋值来重命名 props,如果它们是无效的标识符或 JavaScript 关键字(如 super),则需要这样做
let { super: trouper = 'lights are gonna find me' } = $props();
剩余 props
最后,我们可以使用 剩余属性 来获取,嗯,其余的 props
let { a, b, c, ...others } = $props();
更新 props
组件内部对 prop 的引用在 prop 本身更新时也会更新——当 App.svelte 中的 count 更改时,它也会在 Child.svelte 内部更改。但子组件能够临时覆盖 prop 值,这对于未保存的临时状态很有用 (演示)
app.svelte
<script>
import Child from './Child.<script>
import Child from './Child.svelte';
let count = $state(0);
</script>
<button onclick={() => (count += 1)}>
clicks (parent): {count}
</button>
<Child {count} />';
let count = $state(0);
</script>
<button onclick={() => (count += 1)}>
clicks (parent): {count}
</button>
<Child {count} />
Child
<script>
let { count } = $props();
</script>
<button onclick={() => (count += 1)}>
clicks (child): {count}
</button>
单纯的基本数据类形是可以修改的,子组件修改props 也是可以发生变化,但是如果是是一个对象就不能修改;
子传父 (vue emit)
createEventDispatcher
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
dispatch('temperatureChange', { temperature: acTemperature }); //后面是参数
$bindable。(不建议)
常,props 单向流动,从父组件到子组件。这使得理解数据在应用程序中的流动变得很容易。
在 Svelte 中,组件 props 可以被 绑定,这意味着数据也可以从子组件 向上 流向父组件。您不应该经常这样做,但如果谨慎而适量地使用,它可以简化您的代码。
这也意味着状态代理可以在子组件中被 修改。
!!!!对于普通 props 也可以进行修改,但强烈建议不要这样做 - 如果 Svelte 检测到组件正在修改它“不拥有”的状态,它会发出警告。
模板语法
@render
要渲染一个 代码片段,请使用 {@render ...} 标签。
{#snippet sum(a, b)}
<p>{a} + {b} = {a + b}</p>
{/snippet}
{@render sum(1, 2)}
{@render sum(3, 4)}
{@render sum(5, 6)}
当然可以这样
{@render (cool ? coolSnippet : lameSnippet)()}
可选代码片段
如果代码片段可能未定义——例如,因为它是一个传入的 prop——那么您可以使用可选链来仅在它已定义时渲染它
{@render children?.()}
bind 绑定
数据通常从上到下流动,从父组件到子组件。bind: 指令允许数据以相反的方式流动,从子组件到父组件。
双向绑定
<input bind:value={value} />
<input bind:value />
从 5.6.0 开始,如果 <input> 具有 defaultValue 并且是表单的一部分,则在表单重置时,它将恢复为该值而不是空字符串。请注意,对于初始渲染,绑定的值优先,除非它是 null 或 undefined。
<script>
let value = $state('');
</script>
<form>
<input bind:value defaultValue="not the empty string">
<input type="reset" value="Reset">
</form>
stores
stores是一个对象,它允许通过简单的商店契约以响应方式访问值。该svelte/store模块包含满足此契约的最小商店实现。
对带$前缀的变量的赋值要求该变量是可写商店,并且会导致调用商店的.set方法。
请注意,商店必须在组件的顶层声明 - 例如,不要在if块或函数内部声明。
<script>
import { writable } from 'svelte/store';
const count = writable(0);
console.log($count); // logs 0
count.set(1);
console.log($count); // logs 1
//局部变量(不表示商店值)不能带有$前缀。
$count = 2;
console.log($count); // logs 2
</script>
何时使用stores
在 Svelte 5 之前,商店是创建跨组件响应式状态或提取逻辑的首选解决方案。使用符文,这些用例已大大减少。
- 在提取逻辑时,最好利用符文的通用响应性:你可以在组件的顶层之外使用符文,甚至将它们放入 JavaScript 或 TypeScript 文件中(使用
.svelte.js或.svelte.ts文件结尾) - 在创建共享状态时,你可以创建一个包含所需值的
$state对象,然后操作该状态
export const userState = $state({
name: 'name',
/* ... */
});
App
<script>
import { userState } from './state.svelte';
</script>
<p>User name: {userState.name}</p>
<button onclick={() => {
userState.name = 'new name';
}}>
change name
</button>
上下文 context
大多数状态是组件级状态,其生命周期与组件相同。但是,也存在部分或应用程序范围的状态,也需要以某种方式进行处理。
最简单的方法是创建全局状态并导入它。
export const myGlobalState = $state({
user: {
/* ... */
}
/* ... */
});
sveltekit 路由
-
src/routes是根路由 -
src/routes/about创建了一个/about路由 -
src/routes/blog/[slug]创建了一个带有参数slug的路由,该参数可用于在用户请求/blog/hello-world等页面时动态加载数据
每个路由目录包含一个或多个路由文件,这些文件可以通过其
+前缀识别。+page.svelte
- 所有文件都可以在服务器上运行
- 除了
+server文件外,所有文件都在客户端运行+layout和+error文件适用于子目录以及它们所在的目录
+page.svelte
一个+page.svelte 组件定义了应用程序的一个页面。默认情况下,页面会在服务器上(SSR)渲染初始请求,并在浏览器中(CSR)渲染后续导航。
src/routes/about/+page
<h1>About this site</h1>
<p>TODO...</p>
<a href="/">Home</a>
+layout
到目前为止,我们一直将页面视为完全独立的组件——导航时,现有的+page.svelte 组件将被销毁,一个新的组件将取代它。
但在许多应用程序中,有一些元素应该在每个页面上可见,例如顶级导航或页脚。与其在每个+page.svelte 中重复它们,不如将它们放在布局中
渲染子组件。 (react 中的 omit)
SvelteKit 怎么获取当前路由的实例?
在 SvelteKit 中,你通常不需要获取“路由实例”(因为 SvelteKit 没有像 Vue Router 或 React Router 那样的“router instance”概念),但你可以轻松获取当前路由的相关信息
<!-- src/routes/+page.svelte -->
<script>
import { page } from '$app/stores';
</script>
<!-- 显示当前路径 -->
<p>当前路径: {$page.url.pathname}</p>
<!-- 显示查询参数 -->
<p>查询参数: {$page.url.searchParams.get('q')}</p>
<!-- 如果是动态路由,如 /blog/[slug] -->
{#if $page.params.slug}
<p>文章 slug: {$page.params.slug}</p>
{/if}
✅ 方法二:在 load 函数中获取 url 和 params
在 +page.js 或 +layout.js 的 load 函数中,你可以直接访问路由信息:
// src/routes/blog/[slug]/+page.js
export async function load({ params, url, fetch }) {
const { slug } = params; // ← 动态参数
const searchQuery = url.searchParams.get('highlight'); // ← 查询参数
const post = await fetch(`/api/posts/${slug}`).then(r => r.json());
return {
post,
highlight: searchQuery
};
}
然后在 +page.svelte 中通过 $page.data 使用:
<script>
import { page } from '$app/stores';
</script>
<h1>{$page.data.post.title}</h1>
{#if $page.data.highlight}
<mark>高亮关键词: {$page.data.highlight}</mark>
{/if}
✅ 方法三:编程式导航(类似“路由实例”的操作)
虽然没有 router 实例,但你可以使用 SvelteKit 提供的导航工具:
<script>
import { goto, invalidate } from '$app/navigation';
import { page } from '$app/stores';
function goToProfile() {
goto('/profile'); // 编程式跳转
}
function refreshData() {
// 重新运行当前页面的 load 函数
invalidate();
}
</script>
<button on:click={goToProfile}>去个人页</button>
<button on:click={refreshData}>刷新数据</button>
<p>当前路径: {$page.url.pathname}</p>
goto(url):跳转页面(客户端导航)invalidate():重新加载当前load数据preloadData(url):预加载某个路由的数据
🚫 不要做的事
- ❌ 不要尝试
import router from '...'—— SvelteKit 没有暴露 router 实例。 - ❌ 不要手动解析
window.location—— 在 SSR(服务端渲染)时会出错。始终用$page或load上下文。
✅ 总结:如何“获取当前路由”
| 需求 | 推荐方式 |
|---|---|
| 获取当前路径、参数、查询字符串 | 使用 $page store(在 .svelte 文件中) |
| 在数据加载时获取路由信息 | 在 +page.js 的 load({ params, url }) 中 |
| 页面跳转或刷新 | 使用 goto()、invalidate() 等 $app/navigation 工具 |
| 全局监听路由变化 | 订阅 $page store 即可自动响应变化 |
svelte:component(官方动态组件标签)
<script>
import Home from './Home.svelte';
import About from './About.svelte';
let component = Home;
function switchToAbout() {
component = About;
}
</script>
<button on:click={switchToAbout}>切换到 About</button>
<svelte:component this={component} name="Alice" />