DEMOプロジェクトにあるカウンターアプリだけを写経してみました。
プロジェクトを作成する
プロジェクト作成
npm create svelte@latest sveltekit-counter
? Which Svelte app template?
> Skeleton project
? Add type checking with TypeScript?
> Yes, using TypeScript syntax
# それ以降の質問はお好きにどうぞ。
モジュールインストール
cd sveltekit-counter
npm install
実行してみる
ターミナルにURLが出力されているので、そこにアクセスし、npm run dev
以下の画面が表示されればOKです。
プロジェクト構成を確認してみる
コマンドで作成されたプロジェクトファイルは以下の通りです。 今回触るのはsrcディレクトリ内だけですが、プロジェクト構成の詳細が気になる方はこちらのページを参照してください。
カウンターアプリを作ってみる
今回追加・修正するファイルは以下の通りです。 ファイル名の先頭に「+」があり、ん??と思うかもしれませんが、間違いではありません。
「+」の接頭辞が付いているファイルはルートファイルと呼ばれ、
route内のディレクトリには1つ以上のルートファイルを格納します。 ルートファイルについて詳しく知りたい方は、こちらのページを参照してください。
route内のディレクトリには1つ以上のルートファイルを格納します。 ルートファイルについて詳しく知りたい方は、こちらのページを参照してください。
初期表示される画面の内容をいじってみる
まずは、初期表示されている画面の内容を修正してみましょう。+page.svelte
保存後に画面を確認すると、「Hello, world.」と表示されているはずです。
<h1>Hello, world.</h1>
カウンター用のコードを書く
routesディレクトリの中にファイル「Counter.svelte」を作成します。Counter.svelt
作成したConterコンポーネントを呼び出してみましょう。
<script lang="ts">
let count = 0;
</script>
<div class="counter">
<strong>{count}</strong>
</div>
+page.svelte
画面に「0」と表示されていればOKです。
<script>
import Counter from './Counter.svelte';
</script>
<Counter />
カウントアップ・ダウン用のボタンを追加する
「+」「ー」ボタンを追加し、「count」の値を変更させましょう。Counter.svelte
「ー」「+」ボタンをクリックして、カウントが変わればOKです。
<button on:click={() => (count -= 1)}>
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5" />
</svg>
</button>
<strong>{count}</strong>
<button on:click={() => (count += 1)}>
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5 M0.5,0 L0.5,1" />
</svg>
</button>
<style>
.counter {
display: flex;
margin: 1rem 0;
}
.counter button {
width: 2em;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border: 0;
background-color: transparent;
touch-action: manipulation;
font-size: 2rem;
}
svg {
width: 25%;
height: 25%;
}
path {
vector-effect: non-scaling-stroke;
stroke-width: 2px;
stroke: #444;
}
</style>
アニメーションをつける
springを利用してカウンターのように数字がスクロールして表示させてみます。 コードは以下の通りです。Counter.svelte
動作確認してみましょう。
<script lang="ts">
import { spring } from 'svelte/motion';
let count = 0;
const displayed_count = spring();
$: displayed_count.set(count);
$: offset = modulo($displayed_count, 1);
function modulo(n: number, m: number) {
return ((n % m) + m) % m;
}
</script>
<div class="counter">
<button on:click={() => (count -= 1)}>
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5" />
</svg>
</button>
<div class="counter-viewport">
<div class="counter-digits" style="transform: translate(0, {100 * offset}%)">
<strong class="hidden" aria-hidden="true">{Math.floor($displayed_count + 1)}</strong>
<strong>{Math.floor($displayed_count)}</strong>
</div>
</div>
<button on:click={() => (count += 1)}>
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5 M0.5,0 L0.5,1" />
</svg>
</button>
</div>
<style>
.counter {
display: flex;
margin: 1rem 0;
}
.counter button {
width: 2em;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border: 0;
background-color: transparent;
touch-action: manipulation;
font-size: 2rem;
}
.counter button:hover {
background-color: var(--color-bg-1);
}
svg {
width: 25%;
height: 25%;
}
path {
vector-effect: non-scaling-stroke;
stroke-width: 2px;
stroke: #444;
}
.counter-viewport {
width: 8em;
height: 4em;
overflow: hidden;
text-align: center;
position: relative;
}
.counter-viewport strong {
position: absolute;
display: flex;
width: 100%;
height: 100%;
font-weight: 400;
color: var(--color-theme-1);
font-size: 4rem;
align-items: center;
justify-content: center;
}
.counter-digits {
position: absolute;
width: 100%;
height: 100%;
}
.hidden {
top: -100%;
user-select: none;
}
</style>
「$:」について
コード内に「$:」とありすが、簡単に説明すると「count」の値が変わった時にしか動作しない処理です。reactive
最初なんやこれ??って思ったけど、しばらく使っていると慣れました。$: displayed_count.set(count);
慣れって怖い。
レイアウト用のファイルを作成してみる
routesディレクトリ内に「+layout.svelte」を追加してみましょう。追加後に画面を確認してみると何も表示されなくなっているはずです。 +layout.svelteが存在しない場合は、デフォルトとして以下のコードになっているようです。
+layout.svelte
今回使うことはないですが、ナビゲーションを追加してみましょう。
slotの部分に+page.svelteの内容が表示されると思ってもらえればOKです。
<slot />
+layout.svelte
以下のように+layout.svelteにて、全画面で使うCSSファイルをインポートしてもOKです。
<nav>
<a href="/">Home</a>
<a href="#">About</a>
<a href="#">Settings</a>
</nav>
<div class="app">
<slot />
</div>
+layout.svelte
<script>
import './styles.css';
</script>
ルーティングについて
ナビゲーションの「about」をクリックすると、ページ遷移するようにしてみます。 「http://localhost:[port]/about」でアクセスするイメージです。フォルダとファイルを作成する
以下のように、routesディレクトリ内にaboutフォルダ、+page.svelteファイルを作成します。+layout.svelte
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="#">Settings</a>
</nav>
<div class="app">
<slot />
</div>
about/+page.svelte
ナビゲーションのAboutをクリックし、画面が遷移すればOKです。
<h1>About</h1>
まとめ
ReactやVueと比べると読みやすい気がしているので、しばらく触ってみる予定です。