あなたはプロのフロントエンドエンジニアです。SvelteKitとTailwindで開発を行います。必要なセットアップは完了しています。 BlogCard.svelteでカードコンポーネントを作ります。初心者にもわかるよう書き方を教えてください。
初心者向けに、BlogCard.svelte
の作り方をわかりやすく解説します!
このコンポーネントはブログ記事をカード形式で表示するためのものです。
BlogCard.svelte
は、以下のような構造になっています。
<script>
ブロック
page.svelte
)から渡されるデータをexport let
で受け取る。title
, description
, imageUrl
, link
, tags
, likes
, author
などのプロパティを定義。HTML部分
Tailwind CSSを活用
shadow-md
で影をつけ、ホバー時にhover:shadow-lg
で影を強調rounded-lg
で角を丸くtext-teal-600
でリンクの色を設定<script>
// 親コンポーネントから受け取るデータ
export let title = "記事のタイトル"; // 記事のタイトル
export let description = "記事の概要がここに入ります。"; // 記事の概要
export let imageUrl = ""; // 記事のサムネイル画像URL
export let link = "#"; // 記事の詳細ページへのリンク
export let tags = []; // 記事のタグ(配列)
export let likes = 0; // いいねの数
export let author = { // 著者情報
name: "著者名",
avatar: "",
profileLink: "#",
date: "2025年2月3日(土) 14:59"
};
</script>
<!-- カード全体 -->
<div class="p-3 w-full h-full">
<div class="flex flex-col p-4 rounded-lg h-full bg-white shadow-md hover:shadow-lg transition-shadow duration-300">
<!-- サムネイル(画像がある場合のみ表示) -->
{#if imageUrl}
<div class="mb-2">
<a href={link} target="_blank" class="block">
<img
src={imageUrl}
alt={title}
class="border border-gray-300 rounded-lg p-1 shadow-sm object-cover w-full h-48"
/>
</a>
</div>
{/if}
<!-- 記事タイトル -->
<div class="mb-2 text-sm">
<a href={link} target="_blank" class="text-teal-600 font-semibold hover:underline">
{title}
</a>
</div>
<!-- セパレーター(仕切り線) -->
<div class="border-b-2 border-teal-600 my-1"></div>
<!-- 記事概要 -->
<div class="text-xs my-2 text-gray-500">
{description}
</div>
<!-- セパレーター(仕切り線) -->
<div class="border-b-2 border-teal-600 my-1"></div>
<!-- タグ(タグがある場合のみ表示) -->
<div class="flex flex-wrap text-xs mb-3 gap-2">
{#each tags as tag}
<a href={`bloglist.html?key=${tag}`} target="_blank" class="text-green-600 hover:underline">
#{tag}
</a>
{/each}
</div>
<!-- いいね数 -->
<div class="text-xs text-right mb-2">
<a href={link} target="_blank" class="text-teal-600 flex items-center justify-end gap-1">
{likes} <i class="far fa-heart"></i>
</a>
</div>
<!-- 著者情報(アイコン+名前+日付) -->
<div class="flex justify-between items-center mt-auto">
<div class="flex items-center">
<a href={author.profileLink} target="_blank">
<img
src={author.avatar}
alt={author.name}
class="rounded-full w-12 h-12 object-cover"
/>
</a>
<div class="ml-2 text-gray-500 text-xs">
<div>{author.name}</div>
<div>{author.date}</div>
</div>
</div>
<div>
<a href={link} target="_blank" class="text-teal-600 hover:text-teal-800">
<i class="fas fa-arrow-right fa-2x"></i>
</a>
</div>
</div>
</div>
</div>
このコンポーネントをpage.svelte
で使うには、以下のようにデータを渡します。
<script>
import BlogCard from '$lib/components/BlogCard.svelte';
const blogPost = {
title: "SvelteKitで学ぶ!ButtonコンポーネントとPropsの基本理解ガイド",
description: "本記事では、SvelteKitで再利用可能なButtonコンポーネントを作成する方法と、Props(プロパティ)を使ったデータの受け渡しについて解説します。",
imageUrl: "",
link: "blog.html?bid=1735918461866",
tags: ["SvelteKit", "Buttonコンポーネント", "Props", "export let", "デフォルト値", "再利用可能", "データバインディング", "親コンポーネント", "属性管理", "UI開発"],
likes: 12,
author: {
name: "湯 鵬飛",
avatar: "https://example.com/avatar.jpg",
profileLink: "bloglist.html?userid=PV7gmD9aWcbT24KC022c9FAXPSI3",
date: "2025年2月3日"
}
};
</script>
<BlogCard {...blogPost} />
コンポーネントの分離
BlogCard.svelte
はブログ記事の情報をカードとして表示する専用コンポーネント。page.svelte
では、BlogCard
にデータを渡して表示する。export let
の役割
export let
を使うと、page.svelte
からデータを受け取れる。title
, description
, imageUrl
などがそれに当たる。データの受け渡し
page.svelte
で blogPost
のオブジェクトを作成し、 BlogCard
に渡している。{...blogPost}
で、オブジェクトのすべてのプロパティをそのまま渡せる。BlogCard.svelte
でブログカードを作成page.svelte
でコンポーネントを呼び出し、データを渡すexport let
を使って親からデータを受け取るこれでSvelteKitとTailwindを使ったブログカードが完成しました! 🎉
このまま応用して、さらに機能を追加することも可能です。わからない部分があれば質問してください!🚀
コンポーネントを6回繰り返して表示するには?
Svelteでは、#each
を使ってコンポーネントを繰り返し表示できます。
例えば、BlogCard
を6回表示する場合、page.svelte
で以下のように書けばOKです。
<script>
import BlogCard from '$lib/components/BlogCard.svelte';
// 6つのブログ記事データ
const blogPosts = [
{
title: "SvelteKitで学ぶ!Buttonコンポーネント",
description: "ButtonコンポーネントとPropsの基本について解説。",
imageUrl: "https://source.unsplash.com/400x300/?tech",
link: "blog.html?bid=1",
tags: ["SvelteKit", "Props", "UI開発"],
likes: 12,
author: {
name: "大平 恵美",
avatar: "https://example.com/avatar1.jpg",
profileLink: "#",
date: "2025年2月3日"
}
},
{
title: "SvelteKitでのフォーム入力とバリデーション",
description: "フォームのデータバインディングとバリデーションを実装する方法。",
imageUrl: "https://source.unsplash.com/400x300/?coding",
link: "blog.html?bid=2",
tags: ["フォーム", "バリデーション", "SvelteKit"],
likes: 20,
author: {
name: "山田 太郎",
avatar: "https://example.com/avatar2.jpg",
profileLink: "#",
date: "2025年2月2日"
}
},
{
title: "SvelteKitでAPIを使ってデータ取得",
description: "fetchを使ってAPIからデータを取得する方法。",
imageUrl: "https://source.unsplash.com/400x300/?data",
link: "blog.html?bid=3",
tags: ["API", "fetch", "SvelteKit"],
likes: 18,
author: {
name: "佐藤 花子",
avatar: "https://example.com/avatar3.jpg",
profileLink: "#",
date: "2025年2月1日"
}
},
{
title: "SvelteKitでルーティングを理解する",
description: "ルーティングの基本とページ遷移の仕組みを解説。",
imageUrl: "https://source.unsplash.com/400x300/?navigation",
link: "blog.html?bid=4",
tags: ["ルーティング", "ページ遷移", "SvelteKit"],
likes: 25,
author: {
name: "田中 次郎",
avatar: "https://example.com/avatar4.jpg",
profileLink: "#",
date: "2025年1月30日"
}
},
{
title: "SvelteKitとTailwindで簡単なUIを作成",
description: "Tailwindを活用したコンポーネントの作り方。",
imageUrl: "https://source.unsplash.com/400x300/?ui",
link: "blog.html?bid=5",
tags: ["UIデザイン", "Tailwind", "SvelteKit"],
likes: 30,
author: {
name: "中村 美咲",
avatar: "https://example.com/avatar5.jpg",
profileLink: "#",
date: "2025年1月25日"
}
},
{
title: "SvelteKitでサーバーサイドレンダリングを学ぶ",
description: "SSRとCSRの違い、SvelteKitのサーバーレンダリングを解説。",
imageUrl: "https://source.unsplash.com/400x300/?server",
link: "blog.html?bid=6",
tags: ["SSR", "サーバーサイドレンダリング", "SvelteKit"],
likes: 15,
author: {
name: "小林 健一",
avatar: "https://example.com/avatar6.jpg",
profileLink: "#",
date: "2025年1月20日"
}
}
];
</script>
<!-- #each を使って6つのカードを表示 -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{#each blogPosts as post}
<BlogCard {...post} />
{/each}
</div>
blogPosts
配列 を作成し、6つのブログ記事のデータを格納。#each
構文 を使い、blogPosts
のデータを BlogCard
に渡して繰り返し表示。{...post}
の書き方BlogCard {...post}
は post
オブジェクトの全プロパティを BlogCard.svelte
に渡す簡単な書き方。grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4
grid-cols-1
)、タブレットでは2列 (md:grid-cols-2
)、PCでは3列 (lg:grid-cols-3
) に並ぶ。✅ #each
を使ってデータを繰り返し表示
✅ データの受け渡しは {...post}
で簡単に記述
✅ Tailwindの grid
を使ってレスポンシブなレイアウトに対応
BlogCard
が簡単に表示されます! 🎉カスタマイズしたい場合は、データを増やしたり、表示レイアウトを変えたりするだけでOKです。 🚀
constを使わずにコンポーネントを複数回表示させる方法は可能か。
const
を使わずにコンポーネントを複数回表示する方法const
を使わずに BlogCard
を複数回表示するには、以下の方法があります。
#each
の中で直接オブジェクトを作成<script>
import BlogCard from './BlogCard.svelte';
</script>
{#each [
{
title: "SvelteKitで学ぶ!ButtonコンポーネントとPropsの基本理解",
description: "SvelteKitで再利用可能なButtonコンポーネントの作成方法を紹介します。",
imageUrl: "https://example.com/image1.jpg",
link: "/blog/sveltekit-button-props",
tags: ["SvelteKit", "Props", "UI開発"],
likes: 10,
author: {
name: "大平恵美",
avatar: "https://example.com/avatar1.jpg",
profileLink: "/user/ohiramegumi",
date: "2025年2月5日",
time: "13:14",
}
},
{
title: "SvelteKitでのフォーム入力とバリデーション",
description: "フォームのデータバインディングとバリデーションの方法を解説。",
imageUrl: "https://example.com/image2.jpg",
link: "/blog/sveltekit-form-validation",
tags: ["フォーム", "バリデーション", "SvelteKit"],
likes: 5,
author: {
name: "田中太郎",
avatar: "https://example.com/avatar2.jpg",
profileLink: "/user/tanakataro",
date: "2025年2月6日",
time: "10:30",
}
}
] as post}
<BlogCard {...post} />
{/each}
#each
の外にデータを定義(const
を使わずに let
で変数を定義する方法)
<script>
import BlogCard from './BlogCard.svelte';
let blogPosts = [
{
title: "SvelteKitで学ぶ!ButtonコンポーネントとPropsの基本理解",
description: "SvelteKitで再利用可能なButtonコンポーネントの作成方法を紹介します。",
imageUrl: "https://example.com/image1.jpg",
link: "/blog/sveltekit-button-props",
tags: ["SvelteKit", "Props", "UI開発"],
likes: 10,
author: {
name: "大平恵美",
avatar: "https://example.com/avatar1.jpg",
profileLink: "/user/ohiramegumi",
date: "2025年2月5日",
time: "13:14",
}
},
{
title: "SvelteKitでのフォーム入力とバリデーション",
description: "フォームのデータバインディングとバリデーションの方法を解説。",
imageUrl: "https://example.com/image2.jpg",
link: "/blog/sveltekit-form-validation",
tags: ["フォーム", "バリデーション", "SvelteKit"],
likes: 5,
author: {
name: "田中太郎",
avatar: "https://example.com/avatar2.jpg",
profileLink: "/user/tanakataro",
date: "2025年2月6日",
time: "10:30",
}
}
];
</script>
{#each blogPosts as post}
<BlogCard {...post} />
{/each}
方法 | メリット | デメリット |
---|---|---|
方法 1 (#each 内でオブジェクト作成) |
const を使わずに直接書ける |
コードが長くなりがち |
方法 2 (let を使う) |
変数として管理でき、データ変更も可能 | let を使う必要がある |
✅ const
を使わなくても #each
の中で直接オブジェクトを作成 すればOK!
✅ データを変更したい場合は let
を使って blogPosts
を定義 すれば、動的な更新も可能!
この方法で BlogCard
を 複数回表示 できます 🚀✨
サンプルコードはいらないので、直接オブジェクトを書くメリットとデメリットを教えてほしい。
即座に表示できる
#each
内で直接オブジェクトを定義できるため、シンプルに記述可能。データのスコープを限定できる
let
などの変数を定義しないため、その場限りでデータを使用 できる。関数やAPIの結果をそのまま使える
fetch
などのデータ取得処理を直接 #each
の中に書くことで、変数の管理を省略できる。可読性が低下する
#each
の中にオブジェクトが長くなると、見づらくなりがち。再利用しにくい
let
で変数化すれば、管理しやすくなる。動的なデータ変更が難しい
let
を使わないので、後からデータを変更したり、APIから取得したデータを加工するのが難しい。✅ 静的なデータ(変更しないデータ)なら直接オブジェクト
✅ 動的にデータを変更したり、APIで取得するなら変数 (let
) を使う
➡ 短くて単発なら「直接オブジェクト」、変更や管理が必要なら「変数で定義」! 🚀
constとletの使い分けについて、constは定数、letは変数で合っていますか。varは使いますか。
const
と let
の使い分けはい、const
は定数、let
は変数 という理解で合っています!
ただし、JavaScript の仕様上 const
も「再代入不可の変数」 なので、少し補足します。
const
の特徴const
で宣言した変数は一度代入すると変更できない)const
の例const name = "太郎";
name = "次郎"; // ❌ エラー: 再代入できない
const
で配列・オブジェクトを操作const user = { name: "太郎", age: 25 };
user.age = 26; // ✅ OK: オブジェクトのプロパティは変更できる
const numbers = [1, 2, 3];
numbers.push(4); // ✅ OK: 配列の中身は変更できる
user = {}; // ❌ エラー: `const` で宣言した変数に新しいオブジェクトは代入できない
let
の特徴let
の例let age = 25;
age = 26; // ✅ OK: 再代入できる
let
を使う場面let count = 0;
function increment() {
count += 1; // ✅ OK: let なので値を変更できる
}
var
は使うべきか?✅ 結論: var
は使わない方が良い! 🚫
var
の問題点var
は関数スコープで、ブロックを無視する
if (true) {
var x = 10;
}
console.log(x); // ✅ 10(ブロックの外でも使える) → 予期せぬバグの原因に!
→ let
はブロックの中だけ有効なので、こういったバグを防げる。
var
は再宣言できる
var x = 10;
var x = 20; // ✅ エラーにならない(上書きできる)
→ let
や const
は同じ変数名を再宣言するとエラーになるので、バグを防げる。
const
vs let
vs var
宣言方法 | 再代入 | スコープ | 使うべき? |
---|---|---|---|
const |
❌ できない | ブロック | ほぼ全てのケースで使うべき |
let |
✅ できる | ブロック | 変数を変更する必要がある場合のみ使う |
var |
✅ できる | 関数 | 🚫 使わない(古い書き方) |
const
を使う? let
を使う?✅ 基本は const
を使う
✅ 値を変更する必要がある場合だけ let
を使う
✅ var
は使わない
const name = "太郎"; // 🔹 変更しないなら const
let age = 25; // 🔹 後で変更するなら let
const
を使う場面const user = { name: "太郎", age: 25 };
const greet = () => console.log("こんにちは!");
let
を使う場面for (let i = 0; i < 10; i++) {
console.log(i);
}
let count = 0;
count += 1;
const
と let
を正しく使おう! 🎯✅ 基本は const
、変更が必要なら let
✅ var
はもう使わない! 🚫
✅ スコープ(ブロック or 関数)を意識する
➡ const
をデフォルトにし、let
は必要な時だけ使おう! 🚀
同じカードでも投稿内容が変わって更新されていきます。この場合はletを使うべきなのでは?
✅ 状況:同じカードでも投稿内容が変わる 結論:let を使うべきか? → 状況による
📌 どんな更新方法なのかを考える 投稿内容が一度決まったら変わらない(APIから取得後は固定) → const を使う ユーザーの操作でデータが変わる(新しい投稿を取得・追加) → let を使う リアルタイムでデータが変わる(WebSocketやPollingで更新) → $ ストア(writable)を使うのが最適
📌 それぞれのケースの使い分け 🟢 const を使うケース ✅ APIから取得後、一度データがセットされたら変わらない ✅ #each でループするが、新しくデータを取得しない
🟡 let を使うケース ✅ データが更新される場合(APIから取得・変更する) ✅ ボタンを押したときに新しいデータを取得する場合
🟠 writable ストアを使うケース ✅ リアルタイムで投稿データが更新される(WebSocket、Polling など) ✅ 複数のコンポーネントで同じデータを管理する場合
📌 結論:どれを使う? 状況 使うべきもの データが固定(API取得後に変更しない) const データを更新する(ボタンで取得し直す) let リアルタイムで変更される(WebSocket, Polling) writable ストア
投稿内容を編集して更新することもあるかと思います。この場合は?
let
の使い方結論:投稿を編集して更新するなら let
を使うのが適切!
なぜなら、投稿データが変更される から。
let
を使う理由編集されたデータを更新できる
const
だとデータを変更できないため、編集機能には向かない。let
なら blogPosts
の内容を変更できる。ユーザーが変更した内容を即座に反映
let
で管理すれば、Svelte
のリアクティブ機能 ($:
) で自動的に UI を更新できる。<script>
import BlogCard from './BlogCard.svelte';
// ✅ let を使って投稿データを変更できるようにする
let blogPosts = [
{
id: 1,
title: "SvelteKitで学ぶ!Buttonコンポーネント",
description: "ボタンコンポーネントとPropsの基本を解説。",
link: "/blog/sveltekit-button-props",
tags: ["SvelteKit", "Props"],
likes: 10
},
{
id: 2,
title: "SvelteKitでのフォーム入力とバリデーション",
description: "フォームのデータバインディングの方法を解説。",
link: "/blog/sveltekit-form-validation",
tags: ["フォーム", "バリデーション"],
likes: 5
}
];
// ✅ 編集する投稿を管理するための変数
let editingPost = null;
let newTitle = "";
let newDescription = "";
// 投稿を編集モードにする
function editPost(post) {
editingPost = post;
newTitle = post.title;
newDescription = post.description;
}
// 投稿を更新する
function updatePost() {
if (editingPost) {
editingPost.title = newTitle;
editingPost.description = newDescription;
editingPost = null; // 編集モードを終了
}
}
</script>
<!-- 投稿のリスト -->
{#each blogPosts as post}
<BlogCard {...post} />
<button on:click={() => editPost(post)}>編集</button>
{/each}
<!-- 編集フォーム(投稿が選択された場合のみ表示) -->
{#if editingPost}
<div class="p-4 border rounded-md mt-4">
<h2>投稿を編集</h2>
<input type="text" bind:value={newTitle} class="border p-2 w-full" />
<textarea bind:value={newDescription} class="border p-2 w-full mt-2"></textarea>
<button on:click={updatePost} class="bg-blue-500 text-white px-4 py-2 mt-2">更新</button>
</div>
{/if}
let blogPosts = [...]
let
で管理し、編集時に変更可能に。let editingPost = null
編集ボタン (editPost()
)
editingPost
に現在の投稿をセットし、編集フォームを表示。更新ボタン (updatePost()
)
editingPost
の title
や description
を更新。let
を使う理由const |
let |
|
---|---|---|
投稿内容を編集する | ❌ 変更できない | ✅ 変更できる |
ユーザーの操作でデータを更新 | ❌ エラーになる | ✅ 動的に変更可能 |
編集した内容を即時反映 | ❌ const では不可 |
✅ Svelte のリアクティブ機能で即時更新 |
let
を使うべきケース✅ 投稿の編集・更新がある
✅ データが動的に変わる(APIから取得した新しい投稿をセットする)
✅ リアクティブに UI を更新したい
投稿内容が編集・更新されるなら let
を使うべき!
理由: let
なら Svelte
のリアクティブ機能を活かして UI を自動更新できる! 🚀✨