Deep Dive into Svelte
Svelte の特徴
- Write less code ... 少ないコード量で記述できる
- No Virtual DOM ... 仮想DOMを使用しない
- Truly reactive ... 真にリアクティブ
Getting started
npm create svelte@latest myapp-svelte
cd myapp
npm install
npm run dev
4つほど質問があった。
ここでTypeScript で実装するかも聞かれる。
Need to install the following packages:
create-svelte@5.0.2
Ok to proceed? (y) y
create-svelte version 5.0.2
┌ Welcome to SvelteKit!
│
◇ Which Svelte app template?
│ SvelteKit demo app
│
◇ Add type checking with TypeScript?
│ Yes, using TypeScript syntax
│
◇ Select additional options (use arrow keys/space bar)
│ Add ESLint for code linting, Add Prettier for code formatting, Add Playwright for browser testing, Add Vitest for unit testing
│
└ Your project is ready!
✔ Typescript
Inside Svelte components, use <script lang="ts">
✔ ESLint
https://github.com/sveltejs/eslint-plugin-svelte
✔ Prettier
https://prettier.io/docs/en/options.html
https://github.com/sveltejs/prettier-plugin-svelte#options
✔ Playwright
https://playwright.dev
✔ Vitest
https://vitest.dev
Install community-maintained integrations:
https://github.com/svelte-add/svelte-add
Next steps:
1: cd myapp-svelte
2: npm install (or pnpm install, etc)
3: git init && git add -A && git commit -m "Initial commit" (optional)
4: npm run dev -- --open
Shorthand attributes
<img src={src} alt="A man dances.">
↓ 属性の名前と値の変数が一致している場合、省略できる
<img {src} alt="A man dances.">
コンポーネント名は大文字始まり
コンポーネント名 Nested が大文字で始まっていることにも注目してください。
この命名規則は、ユーザーが定義したコンポーネントと、通常のHTMLタグを区別するために採用されました。
UpperCamelCase なのかな?
アロー関数ではないのが、慣習なのかな?
<script>
let count = 0;
function incrementCount() {
count += 1;
}
</script>
<button on:click={incrementCount}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
リアクティブ宣言 - reactive declarations
<script>
let count = 0;
$: doubled = count * 2;
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
<p>{count} doubled is {doubled}</p>
リアクティブな値は、複数回参照する必要がある場合や、他の リアクティブな値に依存する値がある場合に特に価値があります。
こういう場合かな
<script>
let count = 0;
$: doubled = count * 2;
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
<p>{count} doubled is {doubled}</p>
<p>{count} doubled is {doubled}</p>
<p>{count} doubled is {doubled}</p>
<p>{count} doubled is {doubled}</p>
$:
ではないから、意図した動作にならないコード
<script>
let count = 0;
let doubled = count * 2;
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
<p>{count} doubled is {doubled}</p>
<p>{count} doubled is {doubled}</p>
<p>{count} doubled is {doubled}</p>
<p>{count} doubled is {doubled}</p>
これなら意図した動きにはなる。
$:
の方が良い理由があるのかな?
たしかに冗長な書き方には見える。
<script>
let count = 0;
let doubled = 0;
function handleClick() {
count += 1;
doubled = count * 2;
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
<p>{count} doubled is {doubled}</p>
<p>{count} doubled is {doubled}</p>
<p>{count} doubled is {doubled}</p>
<p>{count} doubled is {doubled}</p>
ロジックを表現する記法
-
{}
を使う - 開始は
#
- 中間は
:
- 終了は
/
<script>
let x = 7;
</script>
{#if x > 10}
<p>{x} is greater than 10</p>
{:else if 5 > x}
<p>{x} is less than 5</p>
{:else}
<p>{x} is between 5 and 10</p>
{/if}
非同期処理
ロジックの記法と同じ
-
{}
を使う - 開始は
#
- 中間は
:
- 終了は
/
<script>
async function getRandomNumber() {
const res = await fetch(`/tutorial/random-number`);
const text = await res.text();
if (res.ok) {
return 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 number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
イベント修飾子
once
で 1 回のみ実行
<script>
function handleClick() {
alert('clicked')
}
</script>
<button on:click|once={handleClick}>
Click me
</button>
イベント修飾子一覧
preventDefault
ハンドラを実行する前に event.preventDefault()
を呼び出します。
たとえば、クライアントのフォーム処理に役立ちます。
stopPropagation
次の要素にイベントが伝播しないように event.stopPropagation()
を呼び出します。
passive
タッチ/ホイールイベントでスクロールのパフォーマンスを向上させます。
(Svelte が安全な場所に自動的に追加します)
nonpassive
passive: false を明示的に設定します。
capture
バブリング フェーズではなく、キャプチャ フェーズ中にハンドラを起動します。
(MDN docs)
once
ハンドラを最初に実行した後に削除します。
self
設定した要素が event.target
の場合にのみ、ハンドラをトリガします。
trusted
event.isTrusted
が true
の場合にのみハンドラをトリガします。
つまり、ユーザーのアクションによってイベントがトリガされた場合です。