Svelte 快速入门
Svelte 在 构建/编译阶段 将你的应用程序转换为理想的 JavaScript 应用,而不是在 运行阶段 解释应用程序的代码。 即它不是像
vue
或React
框架那样,需要在运行时解析(依赖于原框架文件,这也是为什么当你只有一个简单页面时打包后文件也会相对较大),而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
作用域预处理器。
语法
口诀👇🏻
- 被更新的变量的名称必须出现在赋值语句的左侧(也说明为什么数组一些方法不能响应式的原因)。
- 单大括号
{}
为插值语法,一个流程以{# keyword ...}
开始,以{/keyword}
结束,若有中间处理流程{:keyword ...}
,如 条件渲染、列表渲染等。 - 双引号内也可使用
{}
。
创建程序
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>
修饰符
preventDefault
: 调用event.preventDefault()
。stopPropagation
: 禁止冒泡 。passive
: 优化touch
、wheel
事件。passive
: 捕获阶段执行。once
: 仅运行一次事件处理。self
: 仅当 event.target 是元素本身时才会触发事件处理器。
注意: 建议避免内联事件处理程序。 多个修饰符通过
|
组合
事件转发(子向父通信)
通过在子组件中,创建 createEventDispatcher
监听自定义事件并派发 dispatch
。 dispatch: ((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}/>
// 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
不会,所有当使用 splice
、push
等方法时,请使用解构等类似方法替换。
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}]
同名可是后半段。
例如:
- input:
bind:value
- checkbox:
bind:checked
bind:group
: 设置为组,如单选框组,和复选框组。类似 name 的作用,但实际输出的是当前组选中的值。
<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>
还有多出了具有只读属性videoWidth
和videoHeight
属性的绑定。
<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
时取消订阅。
// store.js
import { writable } from 'svelte/store'
export const count = writable(0);
<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 />
: 调用自身组件,类似递归。比如描述一个文件夹树状图时很有用。
<!-- 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="..."
:指定将此组件编译为自定义标签时使用的名称。