Cap1 前言
我为什么要使用它,因为它目前对我来说很适合开发小而快速迭代的项目,而且极致精简。采用尤雨溪解释:Svelte 的核心思想在于『通过静态编译减少框架运行时的代码量』。
这就意味着 Svelte
在浏览器运行中不会存在所谓的 runtime
。至于更多特色请看尤雨溪知乎回答:如何看待 svelte 这个前端框架? 不过这边我不做对此评价,毕竟只有合适自己的工具才是好工具。
学习前提有良好的
HTML
和JS
基础,如果会Vue
上手更快。
Cap2 初始化
npx degit sveltejs/template my-svelte-project
cd my-svelte-project
npm install
npm run dev
或者下载 Svelte 模板进行编写,修改 App.svelte
文件:
<script>
export let name = 'World';
</script>
<section>
<h1 class="hello">Hello {name}!</h1>
</section>
<style>
.hello {
color: red;
}
</style>
上述是它的一个简单的例子,风格看起来和 Vue
很相似。
Cap3 模板语法
Svelte
的模板语法使用 {}
来表达。
标签
Svelte
标签风格和 Vue.js
一样,小写标签代表常规的 HTML
标签,单词首字母大写代表 Svelte
引进来的组件。
Attributes 和 props
风格依然和 Vue.js
一样,但引号他可以忽略不写:
<div class="foo">
<button disabled="{!disabled}">按钮切换</button>
<input disabled={!disabled}/>
</div>
<div class=div></div>
表达式
<h1>Hello {name}!</h1>
<p>{a} + {b} = {a + b}.</p>
条件渲染
{#if porridge.temperature > 28}
<p>太热了</p>
{:else if 12 > porridge.temperature}
<p>太冷了</p>
{:else}
<p>刚刚好</p>
{/if}
列表渲染
语法如下:
<script>
export const items = [{ message: "Foo" }, { message: "Bar" }];
</script>
<section>
<ul>
{#each items as item}
<li>{item.message}</li>
{/each}
</ul>
</section>
<!-- 渲染效果
<section>
<ul>
<li>Foo</li>
<li>Bar</li>
</ul>
</section>
-->
如果需要索引值可以修改:
<script>
export const items = [{ message: "Foo" }, { message: "Bar" }];
</script>
<section>
<ul>
{#each items as item, index}
<li>{index} - {item.message}</li>
{/each}
</ul>
</section>
为了保证区分列表数据的唯一性,需要加入 key
值来区分:
<section>
<ul>
{#each items as item, index (item.id)}
<li>{index} - {item.message}</li>
{/each}
</ul>
</section>
{#each items as { id, name, qty }, i (id)}
<li>{i + 1}: {name} x {qty}</li>
{/each}
{#each objects as { id, ...rest }}
<li><span>{id}</span><MyComponent {...rest}/></li>
{/each}
{#each items as [id, ...rest]}
<li><span>{id}</span><MyComponent values={rest}/></li>
{/each}
如果循环为空的时候使用 {:else}
来表示循环块的占位符:
{#each todos as todo}
<p>{todo.text}</p>
{:else}
<p>没有数据了!</p>
{/each}
{#await ...}
这个用于请求接口业务比较多,请求接口周期分成三大块:请求中,请求成功和请求失败:
<script>
let promise = getRandomNumber();
async function getRandomNumber() {
const res = await fetch(
`https://api.imjad.cn/hitokoto/?charset=utf-8&length=50&encode=json`
);
const text = await res.text();
if (res.ok) {
return JSON.parse(text);
} else {
throw new Error(text);
}
}
</script>
<section>
{#await promise}
<p>正在等待接口响应...</p>
{:then value}
<p>获取到数据: {value.hitokoto}</p>
{:catch error}
<p>获取失败: {error.message}</p>
{/await}
</section>
catch
可以选择性忽略,当然最简洁的写法如下:
{#await promise then value}
<p>获取数据: {value}</p>
{/await}
{@html ...}
这个标签和 Vue.js
中的 v-html
一样,渲染 html
内容:
<script>
let html = `<h3 style="color: #eee">Hello Wold</h3>`
</script>
<section>
{@html html}
</section>
值得注意的是,@html 渲染的标签必须是有效的 html 内容。
{@debug ...}
该标签用于替代 console.log
,当指定的变量名改变时候,他会在控制台记录,并且在 devtools
开启状态下给该变量进行断点测试,方便数据测试。
语法:
{@debug var1, var2, ..., varN}
<script>
let html = `<h3 style="color: #eee">Hello Wold</h3>`
</script>
<section>
{@debug html}
{@html html}
</section>
Cap4 指令元素
这里的指令元素和 Vue
一样,使用上面也差不多,但在 Svelte
上它更显然灵活些。
on:eventname
语法:
on:eventname={handler}
on:eventname|modifiers={handler}
<script>
let count = 0;
function handleClick(event) {
count += 1;
}
</script>
<button on:click={handleClick}>
数量: {count}
</button>
同样支持内联声明函数:
<script>
let count = 0;
</script>
<button on:click="{() => count += 1}">
count: {count}
</button>
修饰符用法:
<form on:submit|preventDefault={handleSubmit}>
</form>
bind:property
bind:property={variable}
用于数据绑定:
<input bind:value={name}>
<textarea bind:value={text}></textarea>
<input type="checkbox" bind:checked={yes}>
如果绑定的属性名相同可以简写如下:
<!-- 俩者效果相同 -->
<input bind:value={value}>
<input bind:value>
可以支持原生的属性绑定。
bind:this
这个属性和 Vue.js
的 ref
一样:
<script>
import { onMount } from "svelte";
let getHelloWorldDom;
onMount(() => {
console.log(getHelloWorldDom);
});
</script>
<div bind:this={getHelloWorldDom}>hello world</div>
class:name
动态绑定 class
属性:
<div class="{active ? 'active' : ''}">...</div>
<div class:active={active}>...</div>
<div class:active>...</div>
<div class:active class:inactive={!active} class:isAdmin>...</div>
use:action
用于创建原生调用的函数,支持销毁方法等。
use:action={parameters}
action = (node: HTMLElement, parameters: any) => {
update?: (parameters: any) => void,
destroy?: () => void
}
<script>
function foo(node) {
// 已经在 dom 挂载
console.log("挂载成功!");
return {
destroy() {
// 已经在 dom 销毁
console.log("销毁成功!");
}
};
}
</script>
<div use:foo />
同样支持更新动作器:
<script>
let bar = false;
function foo(node) {
// 已经在 dom 挂载
console.log("挂载成功!");
return {
update(bar) {
// 当 bar 更新的时候触发
console.log(`bar 更新了`);
},
destroy() {
// 已经在 dom 销毁
console.log("销毁成功!");
}
};
}
function handleClick() {
bar = true;
}
</script>
<div use:foo={bar} />
<button on:click={handleClick}>点击</button>
transition:fn
这边同样请参考 Vue
的 transition
组件。
transition:fn
transition:fn={params}
transition:fn|local
transition:fn|local={params}
transition = (node: HTMLElement, params: any) => {
delay?: number,
duration?: number,
easing?: (t: number) => number,
css?: (t: number, u: number) => string,
tick?: (t: number, u: number) => void
}
{#if visible}
<div transition:fade>
fades in and out
</div>
{/if}
值得注意的是 transition
支持双向转换,意味着将原生平滑反转。
和 use:action
一样支持参数传递:
{#if visible}
<div transition:fade="{{ duration: 2000 }}">
flies in, fades out over two seconds
</div>
{/if}
关于更多动画请参考文档说明,这边不再描述。
Cap5 组件指令
on:eventname
组件事件可以使用 DOM
转发事件和 createEventDispatcher
<SomeComponent on:whatever={handler}/>
<SomeComponent on:whatever/>
bind:property
可以将绑定的值传递给组件:
<Keypad bind:value={pin}/>
bind:this
同样支持 bind:this
传递,可以进行组件交互:
<ShoppingCart bind:this={cart}/>
<button on:click={() => cart.empty()}>
Empty shopping cart
</button>
Cap6 插槽
同样还支持 <solt>
组件,是的,依然和 Vue.js
一样。
支持匿名插槽和具名插槽:
<!-- App.svelte -->
<Widget>
<h1 slot="header">Hello</h1>
<p slot="footer">Copyright (c) 2019 Svelte Industries</p>
</Widget>
<!-- Widget.svelte -->
<div>
<slot name="header">No header was provided</slot>
<p>Some content between header and footer</p>
<slot name="footer"></slot>
</div>
Cap7 组件递归
<svelte:self>
允许组件以递归形式遍历自己,请注意判断表达式,免得出现无限递归。
<script>
export let count = 30;
</script>
{#if count > 0}
<p>counting down... {count}</p>
<svelte:self count={count - 1} />
{:else}
<p>lift-off!</p>
{/if}
Cap8 动态渲染
<svelte:component>
用于动态渲染组件,当属性更改时,该组件被销毁并且重新创建,如果属性是错误的,则不会渲染任何组件。
<!--App.svelte-->
<script>
import RedThing from './RedThing.svelte';
import GreenThing from './GreenThing.svelte';
import BlueThing from './BlueThing.svelte';
const options = [
{ color: '红', component: RedThing },
{ color: '绿', component: GreenThing },
{ color: '蓝', component: BlueThing },
];
let selected = options[0];
</script>
<select bind:value={selected}>
{#each options as option}
<option value={option}>{option.color}</option>
{/each}
</select>
<svelte:component this={selected.component}/>
<!--BlueThing.svelte-->
<style>
strong { color: blue; }
</style>
<strong>蓝色</strong>
<!--GreenThing.svelte-->
<style>
strong { color: green; }
</style>
<strong>绿色</strong>
<!--RedThing.svelte-->
<style>
strong { color: red; }
</style>
<strong>红色</strong>
Cap9 侦听 window 对象
<svelte:window on:event={handler}/>
<svelte:window bind:prop={value}/>
允许将事件侦听到 window
对象里。
<script>
function handleKeydown(event) {
alert(`pressed the ${event.key} key`);
}
</script>
<svelte:window on:keydown={handleKeydown}/>
<svelte:window bind:scrollY={y}/>
支持绑定的值:
-
innerWidth
-
innerHeight
-
outerWidth
-
outerHeight
-
scrollX
-
scrollY
-
online —
window.navigator.onLine
的别名
Cap10 侦听 body 对象
<svelte:body on:event={handler}/>
和 <svelte:window/>
一样,侦听 document.body
事件。
<svelte:body
on:mouseenter={handleMouseenter}
on:mouseleave={handleMouseleave}
/>
Cap11 head
<svelte:head>...</svelte:head>
可以添加一些元素到 <head>
里,在服务器渲染,这边渲染主要的 html
内容,来保良好的 seo
:
<svelte:head>
<link rel="stylesheet" href="tutorial/dark-theme.css">
</svelte:head>
Cap12 编译器配置
<svelte:options option={value}/>
可以配置每个组件的编译的条件:
<svelte:options tag="my-custom-element"/>
可用属性如下:
immutable={true}
- you never use mutable data, so the compiler can do simple referential equality checks to determine if values have changedimmutable={false}
- the default. Svelte will be more conservative about whether or not mutable objects have changedaccessors={true}
- adds getters and setters for the component's propsaccessors={false}
- the defaultnamespace="..."
- the namespace where this component will be used, most commonly "svg"tag="..."
- the name to use when compiling this component as a custom element
Cap13 Svelte 运行
生命周期
和 Vue.js
一样,它也包含生命周期:
-
onMount - DOM 加载好后执行的回调。
-
beforeUpdate - 组件更新前的回调。
-
afterUpdate - 组件更新后立即执行的回调。
-
onDestroy - 组件销毁的运行回调。
tick
promise: Promise = tick()
Returns a promise that resolves once any pending state changes have been applied, or in the next microtask if there are none.
<script>
import { beforeUpdate, tick } from 'svelte';
beforeUpdate(async () => {
console.log('the component is about to update');
await tick();
console.log('the component just updated');
});
</script>
setContext
因为Svelte
不包含 this
,利用该属性可以将上下文对象与当前组件关联,可以使用 getContext
获取上下文信息提供给组件。和生命周期函数一样,必须在组件初始化期间调用它。
<script>
import { setContext } from 'svelte';
setContext('answer', 42);
</script>
getContext
context: any = getContext(key: any)
检索指定的组件上下文 key
,需要在组件初始化期间调用。
createEventDispatcher
创建一个自定义组件事件,语法如下:
dispatch: ((name: string, detail?: any) => void) = createEventDispatcher();
创建的事件不会被冒泡,也无法使用
event.preventDefault()
取消。
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
</script>
<button on:click="{() => dispatch('notify', '详细信息')}">火宅事件</button>
<script>
function callbackFunction(event) {
console.log(`收到通知,详细如下: ${event.detail}`)
}
</script>
<Child on:notify="{callbackFunction}"/>

