Skip to content

Svelte 快速入门

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

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

svelte
<script>
	let name = 'world';
</script>

<h1>Hello {name}!</h1>

<style>
	// ...
</style>

已知缺陷

截止 2023.07.15

Svelte 不支持组件嵌套 class

svelte
<!-- Container.svelte -->
<Button class="red-btn">子按钮</Button>

<style>
  .red-btn {
    background: red;
  }
</style>
svelte
<!-- 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. 双引号内也可使用 {}

创建程序

javascript
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=""

svelte
<button on:click="handleClick">
	按钮
</button>

// 内联方式,"" 是可选的。
<button on:click="{e => ...}">
	按钮
</button>

// 通过管道符 | 来使用修饰符,可组合多个
<button on:click|stopPropagation|passive="handleClick">
	按钮
</button>

修饰符

  • preventDefault : 调用event.preventDefault()
  • stopPropagation : 禁止冒泡 。
  • passive : 优化 touchwheel 事件。
  • passive : 捕获阶段执行。
  • once : 仅运行一次事件处理。
  • self : 仅当 event.target 是元素本身时才会触发事件处理器。

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

事件转发(子向父通信)

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


```svelte
// father.svelte
<script>
	import Child from './Child.svelte';

	function handleMessage(event) {
		alert(event.detail.text);
	}
</script>

<Child on:message={handleMessage}/>
svelte
// 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 等方法时,请使用解构等类似方法替换。

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

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

Props

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

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

svelte
// A.svelte
<script>
	export let name
</script>

// B.svelte
<script>
	import A from './A.svelte'
</script>

<A name="kim"/>

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

svelte
<!-- 通过 单括号 语法绑定 -->
<div class="{ value'active' : '' }"></div>

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

条件渲染

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

列表渲染

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

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

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

异步渲染

svelte
{#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}] 同名可是后半段。

例如

  • input: bind:value
  • checkbox: bind:checked
  • bind:group : 设置为组,如单选框组,和复选框组。类似 name 的作用,但实际输出的是当前组选中的值。
svelte
<script>
	let name = 'world';
</script>

<input bind:value={name}>

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

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

  • duration :视频的总时长,以秒为单位。
  • buffered :数组 {start, end}  的对象。
  • seekable :同上。
  • played:同上。
  • seeking:布尔值。
  • ended:布尔值。

4 个双向 绑定:

  • currentTime :视频中的当前点,以秒为单位。
  • playbackRate :播放视频的倍速, 1 为 '正常'。
  • paused :暂停。
  • volume :音量,0到1之间的值。

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

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

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

  • clientWidth
  • clientHeight
  • offsetWidth
  • offsetHeight

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

生命周期

  • onMount(callback): 挂载完成后执行。
  • onDestroy(callback): 销毁时执行。
  • beforeUpdate(callback): dom 渲染完成前执行。
  • afterUpdate(callback): dom 渲染完成后执行。
  • tick(): 它返回一个带有resolve方法的 Promise,每当组件pending状态变化便会立即体现到DOM中。类似 nextTick

状态管理

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

  • subscribe : 订阅状态,并返回取消订阅函数。
  • update : 更新状态
  • set : 设置状态
  • get:在不订阅情况下读取状态(非响应式)

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

javascript
// store.js
import { writable } from 'svelte/store'
export const count = writable(0);
svelte
<script>
  // other.svelte
  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>

特殊标签

  • <svelte:self /> : 调用自身组件,类似递归。比如描述一个文件夹树状图时很有用
svelte
<!-- Folder.svelte -->
{#if file.type === 'folder'}
	<!-- 原来可能会这么写 <Folder {...file}/> -->
	<svelte:self {...file}/>
{:else}
	<File {...file}/>
{/if}
  • <svelte:component this={component} /> :动态组件,类似 vue 中的 <Component :is="..." />

  • <svelte:window .../> :通过 window 对象给标签添加事件监听。即给 window 添加事件监听。适用于事件监听的语法。

  • <svelte:body .../> :通过 body 对象给标签添加事件监听。简单来说就是监听 body 事件的标签写法。

  • <svelte:head></svelte:head> :插入内容到 <head> 标签。 在服务器端渲染(SSR)模式下, <svelte:head> 中的内容单独返回到HTML中。

  • <svelte:options> : 允许指定编译器选项。

    • immutable={true} :你不能使用可变数据,因此编译器可以通过引用简单的对比检查来确定值是否已更改。
    • immutable={false} :默认值。对于可变对象数据变更,Svelte将其保持不变。
    • accessors={true} :为组件的属性添加getter和setter。
    • accessors={false}:默认。
    • namespace="..." :将使用namespace的组件,最常见的是"svg"
    • tag="..." :指定将此组件编译为自定义标签时使用的名称。

Released under the MIT License.