腳手架
Vite:vite是整合了svelte,初始化的時候選擇svelte就行了。
npm init vite
SvelteKit:底層基於vite的更上層框架,類似於nextjs。
npm create svelte@latest my-app
cd my-app
npm install
npm run dev
.svelte檔案結構
和vue類似svelte檔案是.svelte結尾的檔案,比如demo.svelte。程式碼結構:
<script>
let name = 'hello world';
</script>
<div class="name">
{name}
</div>
<style>
.name {
color: red;
}
</style>
模版繫結
繫結變數
<script>
let name = 'world';
</script>
<h1>Hello {name}!</h1>
繫結屬性
<script>
let src = '/tutorial/image.gif';
let name = '張三';
</script>
<img {src} alt="{name} dances.">
繫結事件
<script>
let count = 0;
function incrementCount() {
count += 1;
}
</script>
<button on:click={incrementCount}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
$:
類似於vue的computed
。例如:
<script>
let count = 0;
// 定義一個名字叫doubled的變數,當count的值改變時,doubled會改變。doubled變數時響應式的。
$: doubled = count * 2;
// 直接這樣寫d2不是響應式的。
let d2 = count * 2;
$: if (count >= 10) {
alert('count is dangerously high!');
count = 9;
}
$: {
console.log('the count is ' + count);
alert('I SAID THE COUNT IS ' + count);
}
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
<p>{count} doubled is {doubled}</p>
<p>
t2 is {d2}
</p>
為什麼d2
變數不是響應式的,我們會在 svelte響應式原理裡面解釋。
if/else
<script>
let user = { loggedIn: false };
function toggle() {
user.loggedIn = !user.loggedIn;
}
</script>
<div>
{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{:else}
<button on:click={toggle}>
Log in
</button>
{/if}
</div>
each遍歷
<script>
let cats = [
{ id: 'J---aiyznGQ', name: 'Keyboard Cat' },
{ id: 'z_AbfPXTKms', name: 'Maru' },
{ id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' }
];
</script>
<h1>The Famous Cats of YouTube</h1>
<ul>
{#each cats as { id, name }, i}
<li><a target="_blank" href="https://www.youtube.com/watch?v={id}" rel="noreferrer">
{i + 1}: {name}
</a></li>
{/each}
</ul>
await
<script>
async function getRandomNumber() {
const res = await fetch(`/tutorial/random-number`);
const text = await res.text();
if (res.ok) {
return {val: text};
} else {
throw new Error(text);
}
}
let promise = getRandomNumber();
function handleClick() {
promise = getRandomNumber();
}
</script>
<button on:click={handleClick}>
generate random number
</button>
{#await promise}
<p>...waiting</p>
{:then res}
<p>The number is {res.val}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
雙向資料流
<script>
let name = 'world';
$:
</script>
<input bind:value={name}>
<h1>Hello {name}!</h1>
元件
使用子元件和父子元件通訊
App.svelte
<script lang="ts">
import Child from './child.svelte';
var num = 1;
var obj = {
count: 1
}
function handleAdd() {
num = num + 1;
obj.count = obj.count + 1;
}
function handleReset(event) {
num = event.detail.val;
obj.count = event.detail.val;
}
</script>
<div>
我是父元件
<button on:click={handleAdd}>add num</button>
// 也支援...的語法
<Child count={num} on:reset={handleReset} />
<Child {...obj} on:reset={handleReset} />
</div>
Child.svelte
<script>
import { createEventDispatcher } from 'svelte';
export let count;
const dispatch = createEventDispatcher();
function handleReset() {
dispatch('reset', {
val: 0
});
}
</script>
<div>
<p>我是子元件,count is {count}</p>
<button on:click={handleReset}>reset count</button>
</div>
元件中使用雙向資料流
App.svelte
<script>
import Child from './child.svelte';
var name;
</script>
<p>
name is {name}
</p>
<Child bind:name />
Child.svelte
<script>
export let name;
</script>
<div>
<input bind:value={name} />
</div>
插槽
App.svelte
<script>
import Child from './child.svelte';
</script>
<Child>
<p>i am from App</p>
<p slot="tool">i am tool</p>
</Child>
Child.svelte
<div>
<slot />
<slot name="tool" />
</div>
生命週期
onMount、onDestroy、beforeUpdate、afterUpdate
<script>
import { onMount, onDestroy, beforeUpdate, afterUpdate } from 'svelte';
onMount(() => {
//...
});
onDestroy(() => {
//...
});
beforeUpdate(() => {
//...
});
afterUpdate(() => {
//...
});
</script>
<h1>Photo album</h1>