開発ブログ

株式会社Nextatのスタッフがお送りする技術コラムメインのブログ。

電話でのお問合わせ 075-744-6842 ([月]-[金] 10:00〜17:00)

  1. top >
  2. 開発ブログ >
  3. Javascript >
  4. Svelte >
  5. Svelte3で問い合わせフォーム作ってみた!

Svelte3で問い合わせフォーム作ってみた!

こんにちは。
ニシザワです。


本日は、GitHubのスター数がかなり増えてきているフロントエンドフレームワークのSvelte(スベルト)について書きたいと思います。
Svelteを学ぶために、簡単な問い合わせフォームを作ってみたのでそちらを使ってご紹介いたします
Svelte使ってますか??

最初に個人的な感想

  • 直感的に書けるのでわかりやすい
  • TypeScriptを簡単に導入できる(Svelte-tsってのが用意されてる)
  • Vue.jsに似ているので元々Vue.jsを書いてた人はすぐ入りやすい

環境

  • NodeJs: v16.15.1
  • Svelte: 3.48.0
  • Vite: 2.9.12
  • TypeScript: 4.7.4

環境構築

環境構築していきます。

Svelteアプリケーションの構築

公式でも推奨されているViteを使ってアプリケーションを作成していきます。
Viteはざっくりいうと超高速にコンパイル&ホットリロードしてくれる開発サーバ付きのビルドツール。
爆速すぎてびっくりします。
ちなみに、Viteはフランス語で素早いという意味らしいです。なっとく。

npm init vite@latest

✔ Project name: … svelte-contact
✔ Select a framework: › svelte
✔ Select a variant: › svelte-ts

cd svelte-contact
npm i && npm run dev


> svelte-contact@0.0.0 dev
> vite


  vite v2.9.12 dev server running at:

  > Local: http://localhost:3000/
  > Network: use `--host` to expose

  ready in 197ms.
viteでプロジェクトを簡単に作成することができます。

svelte-routingをインストール

次に今回はページ遷移(問い合わせ,確認,完了)があるので
svelte-routingをインストールします。

npm i -D svelte-routing

その他

バリデーションにsvelte-use-formを入れてます。
個人的に色々と試した中で一番直感的でわかりやすかったので。
見た目にbulmaも入れてます。

npm i -D bulma
これで準備完了です。

問い合わせフォームを作成

それでは、作成していきます。

状態管理

まず、問い合わせフォームで必要な情報を状態管理したいのでそちらを書いていきます。
Svelteは最初から状態管理できる仕組みであるストアが用意されています。
src/store/contact/Contact.ts

import { Writable, writable } from 'svelte/store';

export interface Contact {
    name: string
    nameKana: string
    email: string
    inquiry: string
}

export const contact: Writable<Contact> = writable(
    {
        name: "",
        nameKana: "",
        email: "",
        inquiry: ""
    }
);
Writableを使って状態を定義すると値の更新及び取得が可能なストアを作ることが可能となっています。

Routerの設定

src/App.svelte

<script lang="ts">
    import { Router, Link, Route } from "svelte-routing";
    import ContactIndex from "./pages/contact/ContactIndex.svelte";
    import ContactConfirm from "./pages/contact/ContactConfirm.svelte";
    import ContactSubmit from "./pages/contact/ContactSubmit.svelte";
    import 'bulma/css/bulma.css';
</script>
<Router>
    <div class="container">
        <nav class="navbar">
            <div class="navbar-menu">
                <div class="navbar-start">
                    <Link to="/" class="navbar-item">Contact</Link>
                </div>
            </div>
        </nav>
        <main>
            <Route path="/">
                <ContactIndex/>
            </Route>
            <Route path="/confirm">
                <ContactConfirm/>
            </Route>
            <Route path="/submit">
                <ContactSubmit/>
            </Route>
        </main>
    </div>
</Router>
Router, Link, Routeが先程インストールしたsvelte-routingの仕組みです。
Routerの中でLinkを入れると、aタグが挿入されて、文字通りリンクを作成してくれます。
Routeは読み込むページを指していて、pathをしてするとそのpathにアクセスがあった時にSvelteComponentを呼び出してくれます。

問い合わせフォーム(入力画面)

さて、入力画面を作っていきます。
src/pages/contact/ContactIndex.svelte
Svelteは.svelteの拡張子で定義していきます。

<script lang="ts">
    import { contact } from "../../store/contact/Contact";
    import { navigate } from "svelte-routing";
    import { useForm, Hint, validators, required, maxLength, HintGroup, email } from "svelte-use-form";

    const form = useForm();

    const onSubmit = (() => {
        navigate('/contact/confirm');
    });

    const onReset = (() => {
        contact.set({name: "", nameKana: "", email: "", inquiry: ""})
        $form.reset();
    });
</script>

<svelte:head>
    <title>お問い合わせフォーム</title>
</svelte:head>

<h1>お問い合わせフォーム</h1>
<form use:form>
    <div class="field">
        <label class="label" for="name">お名前</label>
        <div class="control">
            <input class="input" bind:value={$contact.name} id="name" name="name"
                   use:validators={[required, maxLength(255)]}/>
            <HintGroup for="name">
                <Hint on="required" class="help is-danger">お名前は必須です。</Hint>
                <Hint on="maxLength" class="help is-danger" hideWhenRequired>お名前は255文字以内で入力してください。</Hint>
            </HintGroup>
        </div>
    </div>

    <div class="field">
        <label class="label" for="nameKana">お名前(カナ)</label>
        <div class="control">
            <input class="input" bind:value={$contact.nameKana} id="nameKana" name="nameKana"
                   use:validators={[maxLength(255)]}/>
            <Hint for="nameKana" class="help is-danger" on="maxLength">お名前(カナ)は255文字以内で入力してください。</Hint>
        </div>
    </div>

    <div class="field">
        <label class="label" for="email">メールアドレス</label>
        <div class="control">
            <input class="input" bind:value={$contact.email} id="email" type="email" name="email"
                   use:validators={[required, email]}/>
            <HintGroup for="email">
                <Hint on="required" class="help is-danger">メールアドレスは必須です。</Hint>
                <Hint on="email" class="help is-danger" hideWhenRequired>メールアドレスの形式で入力してください。</Hint>
            </HintGroup>
        </div>
    </div>

    <div class="field">
        <label class="label" for="inquiry">お問い合わせ内容</label>
        <div class="control">
    <textarea class="textarea" bind:value={$contact.inquiry} id="inquiry" name="inquiry"
              use:validators={[required, maxLength(10000)]}></textarea>
            <HintGroup for="inquiry">
                <Hint on="required" class="help is-danger">お問い合わせ内容は必須です。</Hint>
                <Hint on="maxLength" class="help is-danger" hideWhenRequired>お問い合わせ内容は1万文字以内で入力してください。</Hint>
            </HintGroup>
        </div>
    </div>

    <div class="field is-grouped">
        <div class="control">
            <button class="button is-link" disabled={!$form.valid} on:click|preventDefault={onSubmit}>確認</button>
        </div>
        <div class="control">
            <button class="button is-link is-light" on:click|preventDefault={onReset}>リセット</button>
        </div>
    </div>
</form>

Svelteではストアの変数のプリフィックスとして$をつけると値の出し入れが可能になっています。便利ですね。
また、コード補完もしっかりしているので、IDE使ってる方はかなり使いやすいかと思います。
navigate関数を使うことで、TS上からも画面遷移させることが可能です。

お問い合わせフォーム(確認)

src/pages/contact/ContactConfirm.svelte

<script lang="ts">
    import { onMount } from 'svelte';
    import { contact } from "../../store/contact/Contact";
    import { navigate } from "svelte-routing";

    onMount(async () => {
        if (!$contact.name || !$contact.email || !$contact.inquiry) {
            navigate('/contact');
        }
    });

    const onSubmit = (() => {
        navigate('/contact/submit');
    });

    const onCancel = (() => {
        navigate('/contact');
    });
</script>

<svelte:head>
    <title>お問い合わせフォーム</title>
</svelte:head>

<h1>お問い合わせフォーム(確認)</h1>
<form>
    <div class="field">
        <label class="label" for="name">お名前</label>
        <div class="control">
            <input disabled class="input" bind:value={$contact.name} id="name" name="name"/>
        </div>
    </div>

    <div class="field">
        <label class="label" for="nameKana">お名前(カナ)</label>
        <div class="control">
            <input disabled class="input" bind:value={$contact.nameKana} id="nameKana" name="nameKana"/>
        </div>
    </div>

    <div class="field">
        <label class="label" for="email">メールアドレス</label>
        <div class="control">
            <input disabled class="input" bind:value={$contact.email} id="email" type="email" name="email"/>
        </div>
    </div>

    <div class="field">
        <label class="label" for="inquiry">お問い合わせ内容</label>
        <div class="control">
            <textarea disabled class="textarea" bind:value={$contact.inquiry} id="inquiry" name="inquiry"></textarea>
        </div>
    </div>

    <div class="field is-grouped">
        <div class="control">
            <button class="button is-link" on:click|preventDefault={onSubmit}>送信</button>
        </div>
        <div class="control">
            <button class="button is-link is-light" on:click|preventDefault={onCancel}>戻る</button>
        </div>
    </div>
</form>
SvelteのonMountで問い合わせフォーム(入力)からこなかった場合はリセットして、入力画面に遷移するように書いています。

お問い合わせフォーム(完了)

src/pages/contact/ContactSubmit.svelte

<script lang="ts">
    import { onMount } from 'svelte';
    import { contact } from "../../store/contact/Contact";
    import { navigate } from "svelte-routing";

    onMount(async () => {
        if (!$contact.name || !$contact.email || !$contact.inquiry) {
            contact.set({name: "", nameKana: "", email: "", inquiry: ""})
            navigate('/contact');
        }
        contact.set({name: "", nameKana: "", email: "", inquiry: ""})
    });
</script>

<h1>完了</h1>
完了ページです。こちらも直接アクセスがあった場合は入力画面に遷移するようにしています。
完了ページがhタグだけなのはちょっと面倒になったんで割愛w。

まとめ

Svelteで簡単な問い合わせフォームを作成しました。
Vue.jsみたいに状態管理を別のライブラリ入れなくても用意されているのが非常に好感を持つことができますね。
また、コード補完が優れているのでIDE使ってる方も非常に書きやすく設計されてます。
※弊社はWebフロントエンジニアにはWebStormを支給してます
まだまだ、やりだしたばかりなので簡単なことしか書けてませんが、今後使っていこうかと思っていますのでまた記事にしたいと思います。
TOPに戻る