Svelte 快速入门

Svelte 快速入门

Jul 05, 2023 ·
11 Min Read

Svelte 在 构建/编译阶段 将你的应用程序转换为理想的 JavaScript 应用,而不是在 运行阶段 解释应用程序的代码。 即它不是像 vueReact 框架那样,需要在运行时解析(依赖于原框架文件,这也是为什么当你只有一个简单页面时打包后文件也会相对较大),而 Svelte 是将你所有语法都编译成普通的 js ,没有任何魔法,这导致只是简单页面的时候打包后会非常小,但会随着页面的复制度增加,可能会出现文件大小暴增。

它像是 Vue 的模式,使用模板 .svelte

<script>
let name = 'world';
</script>
<h1>Hello {name}!</h1>
<style>
// ...
</style>

已知缺陷

截止 2023.07.15

Svelte 不支持组件嵌套 class

Container.svelte
<Button class="red-btn">子按钮</Button>
<style>
.red-btn {
background: red;
}
</style>
Button.svelte
<button class="btn {$$props.class}"><slot></slot></Button>
<style>
.btn {
background: blue;
}
</style>

结果会渲染为 蓝色按钮,red-btn class 无效。

关于这个问题的issue 👉🏻 Support classes on nested components 大概得意思就是因为作者认为组件的控制权应该由组件自身控制,不应该外部可以覆盖的。导致这个问题的原因是 svelte 自身的class 优化,Button 组件上的 red-btn 会因为判断为未使用因此被删除。 解决方案:可以通过 :global() 绕过 或 使用 svelte-preprocess-cssmodules 作用域预处理器

语法

口诀👇🏻

  1. 被更新的变量的名称必须出现在赋值语句的左侧(也说明为什么数组一些方法不能响应式的原因)。
  2. 单大括号 {} 为插值语法,一个流程以 {# keyword ...} 开始,以 {/keyword} 结束,若有中间处理流程 {:keyword ...},如 条件渲染、列表渲染等。
  3. 双引号内也可使用 {}

创建程序

import App from './App.svelte';
const app = new App({
target: document.body,
props: {
// we'll learn about props later
answer: 42
}
});

事件处理

语法on:event="handleFunction" 如:on:click=""

<button on:click="handleClick">
按钮
</button>
// 内联方式,"" 是可选的。
<button on:click="{e => ...}">
按钮
</button>
// 通过管道符 | 来使用修饰符,可组合多个
<button on:click|stopPropagation|passive="handleClick">
按钮
</button>

修饰符

注意: 建议避免内联事件处理程序。 多个修饰符通过 | 组合

事件转发(子向父通信)

通过在子组件中,创建 createEventDispatcher 监听自定义事件并派发 dispatchdispatch: ((name: string, detail?: any) => void) = createEventDispatcher()

father.svelte
```svelte
<script>
import Child from './Child.svelte';
function handleMessage(event) {
alert(event.detail.text);
}
</script>
<Child on:message={handleMessage}/>
Child.svelte
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
function sayHello() {
// 派发事件
dispatch('message', {
text: 'Hello!'
});
}
</script>
<button on:click={sayHello}>
Click to say hello
</button>

如果是深层嵌套传递自定义事件,若组件无需赋予特定值(即操作 e.detail),可以简写为 on:evnet 。如 Child.svelte 无需修改 e.detail 可简写为 on:message

侦听器

语法$ [{]...[}] 如:$: double = count * 2 ,每当 count 改变时,自动触发。double 可以不用提前声明。

数组更新

注意:在 vue 因为 splice 等方法被重写了,因此会触发自动更新;而 svelte 不会,所有当使用 splicepush 等方法时,请使用解构等类似方法替换。

a.push(b) // 不会触发页面更新
a = [...a, b] // 可以触发页面更新

口诀:被更新的变量的名称必须出现在赋值语句的左侧。

Props

组件的props 声明,并不像 vue or react 那样,而是通过 export 来声明; 语法export let propname

注意:可以通过 $$props 直接获取所有 props ,即使未被 export 的,但不建议,因为不利于优化。如果添加了默认值(包括 undefind),则改 prop 为可选

A.svelte
<script>
export let name
</script>
// B.svelte
<script>
import A from './A.svelte'
</script>
<A name="kim"/>

可以通过 {} 来进行动态绑定或使用特殊指令。 svelte style 默认是 module 即样式模块化

<!-- 通过 单括号 语法绑定 -->
<div class="{ value'active' : '' }"></div>
<!-- 通过指令绑定 -->
<!-- 当 value 为真时,绑定 active 类 -->
<div class:active="{value}"></div>

条件渲染

{#if a}
...other
{:else b}
...other
{:else}
...other
{/if}

列表渲染

第一个参数迭代项别名,第二个参数当前项位置索引(可选)

// item 也可以使用解构
{#each items as item, index}
...other
{/each}

默认按照 “就地更新” 的策略来更新通过 each 渲染的元素列表。当数据项的顺序改变时,就地更新每个元素,可能并不是你想要的效果,类似 vue v-for 不添加 key 时效果。 svelte 通过在 item 后添加 (key) 来为每一项添加唯一 key,支持任何类型,但建议数值或字符串。如:{#each items as item(item.id)}

异步渲染

{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}

解析 html

更新元素的 innerHTML。类似 v-html语法{@html ...}

数据绑定

将(部分自身 or 自定义)属性与变量进行双向绑定。类似 v-model 效果。 语法:bind:property[={variable}] 同名可是后半段。

例如

<script>
let name = 'world';
</script>
<input bind:value={name}>

注意:bind:value 可能是数组,在于它用于哪里,如 select multile

video & audio 同样支持部分属性绑定 🆙 针对 <audio> 和 <video> 的 6 个只读属性绑定 :

4 个双向 绑定:

<video> 还有多出了具有只读属性videoWidthvideoHeight 属性的绑定。

<video
src="https://sveltejs.github.io/assets/caminandes-llamigos.mp4"
bind:currentTime={time}
bind:duration
bind:paused
></video>

块级标签 不建议大量使用❗❗❗ 4个只读属性进行绑定 :

模板引用 获取标签或组件的引用。 语法:bind:this={ref} 类型其他框架的 ref 属性。

生命周期

状态管理

store 模块导出函数可用于创建 readable 可读 , writable 可写, 和 derived 派生的 store。 高级功能:还可自定义 store

store = writable(value: any, (set: (value: any) => void) => () => void) 第一参数 value 初始值;第二参数函数在 subscribe 触发时执行,且必须返回一个函数

store = readable(value: any, (set: (value: any) => void) => () => void) 第一参数 value 初始值;第二参数与 writable 一致,但只能通过它来修改值,外部无法修改。

store = derived(a, callback: (a: any, set: (value: any) => void) => void | () => void, initial_value: any) store = derived([a, ...b], callback: ([a: any, ...b: any[]], set: (value: any) => void) => void | () => void, initial_value: any) 一个源于一个或多个其他 store的store,只要这些依赖项发生变更,就会执行回调。类似 vue watch

注意:订阅后必须在 onDestroy 时取消订阅。

store.js
import { writable } from 'svelte/store'
export const count = writable(0);
other.svelte
<script>
import { onDestroy } from 'svelte'
import { count } from './stores.js'
// 更新
count.update(n => n+1)
// 重置
count.set(0)
// 订阅
let count_value
const unsubscribe = count.subscribe(value => {
count_value = value
})
onDestroy(unsubscribe)
</script>
<div>{count_value}</div>
// 或者直接使用 $ 符语法订阅,并且可以用在任何地方,因此在 svelte 中不允许用户用 $ 前缀声明变量。
<div>{$count}</div>

特殊标签

Folder.svelte
{#if file.type === 'folder'}
<!-- 原来可能会这么写 <Folder {...file}/> -->
<svelte:self {...file}/>
{:else}
<File {...file}/>
{/if}
Last edited Feb 15