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
<Button class="red-btn">子按钮</Button>
<style> .red-btn { background: red; }</style><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<script> import Child from './Child.svelte';
function handleMessage(event) { alert(event.detail.text); }</script>
<Child on:message={handleMessage}/><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 为可选。
<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个只读属性进行绑定 :
clientWidthclientHeightoffsetWidthoffsetHeight
模板引用
获取标签或组件的引用。
语法: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时取消订阅。
import { writable } from 'svelte/store'export const count = writable(0);<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>特殊标签
<svelte:self />: 调用自身组件,类似递归。比如描述一个文件夹树状图时很有用。
{#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="...":指定将此组件编译为自定义标签时使用的名称。