はじめに
この記事は前回投稿した記事
最近名前をよく見かけるsvelte/sapperを試してみた ~その1 導入編~
の続きの記事になります。
今回は、 svelte
の構文について、メインに取り上げていきたいと思います。
参考リンク
前提
今回は前回作成したプロジェクトの、
sapper_sample/src/routes/index.svelte
(笑顔のおじさんが映っているページ)のファイルを修正していきつつ、構文の確認を行いたいと思います。
現状は下記のようになっています。
(style部分は除く)
<head>
<title>Sapper project template</title>
</head>
<h1>Great success!</h1>
<figure>
<img alt='Borat' src='great-success.png'>
<figcaption>HIGH FIVE!</figcaption>
</figure>
<p><strong>Try editing this file (src/routes/index.svelte) to test live reloading.</strong></p>

それでは始めていきます!
(長くなるので追加部分のみ記載しています。ご了承ください。)
構文
if/else
<script>
let state = { switch: false };
function toggle() {
state.switch = !state.switch;
}
</script>
{#if state.switch}
<button on:click={toggle}>
スイッチON
</button>
<div>スイッチONだよ!</div>
{:else}
<button on:click={toggle}>
スイッチOFF
</button>
<div>スイッチOFFだよ!</div>
{/if}
上記を実行すると、下記のようにクリックでスイッチのON/OFFが切り替わるようなボタンを設置することができます。
each
<script>
let members = [
{ name: 'たろー', gender: '男性' },
{ name: 'じろー', gender: '男性' },
{ name: 'はなこ', gender: '女性' },
{ name: 'さぶろー', gender: '男性' }
];
</script>
<ul>
{#each members as { name, gender }, i}
<li>
{i + 1}: {name} {gender}
</li>
{/each}
</ul>
上記を実行すると、定義したリストに応じた情報(ここの例ではメンバー)が表示されます。簡単ですね。
await
<script>
let promise = getName();
async function getName() {
// 遅延させる
await new Promise(r => setTimeout(r, 5000));
return "JIRO"
}
</script>
{#await promise}
<p style="font-size:20px;color:#f00;">...waiting</p>
{:then member}
<p style="font-size:20px;">{member}</p>
{/await}
上記を実行すると、async関数が値(ここではJIRO)を返すまで、 ...waiting
の文字が表示されます。
リアクティブ
<script>
let count = 0;
function handleClick() {
count += 1;
}
</script>
<figure on:click={handleClick}>
<img alt='Borat' src='great-success.png'>
<figcaption>HIGH FIVE!</figcaption>
</figure>
<div style="text-align: center;">
<div style="font-size:20px;">
クリック回数:{count}
</div>
</div>
上記を実行すると、 figure
要素(おじさん写真)をクリックするたびに、数字がインクリメントされます。
(下記画像ではおじさんを連打しています。)
ちなみに下記のようにすると、クリックした回数×2,3が画面に表示されるようになります。
<script>
let count = 0;
$: doubled = count * 2;
$: tripled = count * 3;
function handleClick() {
count += 1;
}
</script>
<figure on:click={handleClick}>
<img alt='Borat' src='great-success.png'>
<figcaption>HIGH FIVE!</figcaption>
</figure>
<div style="text-align: center;">
<div style="font-size:20px;">
クリック回数:{count}
</div>
<div style="font-size:20px;">
クリック回数×2:{doubled}
</div>
<div style="font-size:20px;">
クリック回数×3:{tripled}
</div>
</div>

$:の意味は?
上記の例で $:
が出てきましたが、
$:
ラベルが付与された式や文は、変数の更新のたびに再計算されるようになります。
この時、 let
等は不要になります。
代入やバインドと関係のない変数に対して、再計算を行いたい場合に用います。
データバインディング
textbox
<script>
let input_text = '';
</script>
<div style="text-align:center; font-size:20px;">
<input bind:value={input_text} placeholder="入力してください。">
<p>{input_text }!</p>
</div>
上記を実行すると、 テキストボックスに入力した文字が、その下に即時反映されます。
checkbox
<script>
let check_status = false;
</script>
<div style="text-align: center;font-size:20px;">
<label>
<input type=checkbox bind:checked={check_status}>
ここをチェック!
</label>
{#if check_status}
<p>チェックしてくれてありがとう( ⁎ᵕᴗᵕ⁎ )</p>
{:else}
<p>チェックしてください(´・ω・`)</p>
{/if}
</div>
上記を実行すると、 チェック可否によって文字が変更されます。
selectbox
<script>
let questions = [
{ id: 1, text: `このおじさんの名前は?` },
{ id: 2, text: `このおじさんの年齢は?` },
];
let selected;
let answer = '';
let message = ``;
function handleSubmit() {
message = `質問:「${selected.text}」 答え:「${answer}」`
}
</script>
<form on:submit|preventDefault={handleSubmit}>
<div>
<div style="text-align: center">
<select bind:value={selected} on:change="{() => answer = ''}" style="font-size:20px;">
{#each questions as question}
<option value={question}>
{question.text}
</option>
{/each}
</select>
</div>
<div style="text-align: center">
<input bind:value={answer} style="font-size:20px;">
<button disabled={!answer} type=submit style="font-size:20px;">
Submit
</button>
<div style="font-size: 24px;color: #f00;">{message}</div>
</div>
</div>
</form>
上記を実行すると、 セレクトボックスの内容、テキストボックスの内容を表示します。
トランジション
<script>
import { fade } from 'svelte/transition';
let visible = true;
</script>
<div style="text-align: center;margin-bottom:40px; font-size:20px;">
<label>
<input type="checkbox" bind:checked={visible}>
表示する
</label>
</div>
{#if visible}
<figure transition:fade>
<img alt='Borat' src='great-success.png'>
<figcaption>HIGH FIVE!</figcaption>
</figure>
{/if}
上記を実行すると、 チェック可否によっておじさんがフェードインされます。
(GIFアニメがちょっと早かったです・・・。)
CSSと組み合わせて、下記のようなものも作れます。
<script>
import { fade } from 'svelte/transition';
import { elasticOut } from 'svelte/easing';
let visible = true;
function spin(node, { duration }) {
return {
duration,
css: t => {
const eased = elasticOut(t);
return `
transform: scale(${eased}) rotate(${eased * 1080}deg);
color: hsl(
${~~(t * 360)},
${Math.min(100, 1000 - 1000 * t)}%,
${Math.min(50, 500 - 500 * t)}%
);`
}
};
}
</script>
<label>
<input type="checkbox" bind:checked={visible}>
実行
</label>
{#if visible}
<div class="centered" in:spin="{{duration: 8000}}" out:fade>
<span>GREAT SUCCESS!</span>
</div>
{/if}

まとめ
今回はsvelteの基本的な構文について触れました。だいぶ直感的に描けますので、わかりやすいです。
まだまだ紹介しきれていないこと、色々なことができますので、ご興味のある方は
svelteのサンプル集、svelteドキュメントを参考に試していただければと思います!
次回は、何か一つ簡単なアプリケーションを作成していこうかと考えています。
読んで頂きありがとうございました!