Help us understand the problem. What is going on with this article?

最近名前をよく見かけるsvelte/sapperを試してみた ~その2 構文編~

はじめに

この記事は前回投稿した記事
最近名前をよく見かけるsvelte/sapperを試してみた ~その1 導入編~
の続きの記事になります。

今回は、 svelte の構文について、メインに取り上げていきたいと思います。

参考リンク

svelteのサンプル集
svelteドキュメント

前提

今回は前回作成したプロジェクトの、
sapper_sample/src/routes/index.svelte
(笑顔のおじさんが映っているページ)のファイルを修正していきつつ、構文の確認を行いたいと思います。
現状は下記のようになっています。
(style部分は除く)

index.svelte
<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

index.svelte
<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

index.svelte
<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

index.svelte
<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 の文字が表示されます。

リアクティブ

index.svelte
<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が画面に表示されるようになります。

index.svelte
<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

index.svelte
<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

index.svelte
<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

index.svelte
<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>

上記を実行すると、 セレクトボックスの内容、テキストボックスの内容を表示します。

トランジション

index.svelte
<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と組み合わせて、下記のようなものも作れます。

index.svelte
<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ドキュメントを参考に試していただければと思います!

次回は、何か一つ簡単なアプリケーションを作成していこうかと考えています。
読んで頂きありがとうございました!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした