SNSアプリを作ってみたいと思ったことはありませんか?
Vue.jsを使えば、意外と簡単に「投稿→表示」の流れを再現することができます。今回は、自分専用のミニTwitter風アプリをVue.jsだけで作ってみましょう。
他人と共有はできない、あくまでローカル限定の”ひとりツイート”アプリですが、Vueの基本を身につけるにはピッタリの題材です。HTML・CSS・JavaScript(Vue)をファイルで分離して、より現実的な構成にも対応しています。
この記事では、次のような内容を順を追って解説していきます。

HTMLの実装
まずはアプリの骨組みとなるHTMLを作っていきましょう。Vue.jsは基本的に1つの要素をマウントポイントとして扱うため、#appというIDを持つdiv要素を中心に構成します。
以下が今回使うindex.htmlの全体構造です。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ツイートアプリ</title>
<link rel="stylesheet" href="style.css">
<script src="https://unpkg.com/vue@3.4.30/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<div class="tweet-box">
<textarea v-model="newTweet" placeholder="いまどうしてる?"></textarea>
<button @click="postTweet">ポストする</button>
</div>
<div class="tweet" v-for="tweet in tweets" :key="tweet.id">
<div class="avatar"></div>
<div class="tweet-content">
<p class="username">@example_user</p>
<p class="text">{{ tweet.text }}</p>
</div>
</div>
</div>
<script src="js.js"></script>
</body>
</html>HTML💡 各要素の意味
- v-model=”newTweet”
双方向バインディングにより、テキストエリアの内容がVueのデータnewTweetとリアルタイムで同期されます。 - @click=”postTweet”
ボタンをクリックすると、postTweetというメソッドが実行され、投稿処理が行われます。 - v-for=”tweet in tweets”
配列tweetsに格納された投稿を1件ずつループ表示します。
:key=”tweet.id”でパフォーマンスを最適化します。 - {{ tweet.text }}
各投稿の本文を表示しています。
CSSでTwitter風にスタイリング
HTMLだけでは見た目がとても素っ気ないので、ここでCSSを使ってTwitter風に整えていきます。ダークモード風の配色、カード型の投稿、角丸のアバターなど、SNSらしい雰囲気を再現します。
以下はstyle.cssのコードです。
body {
margin: 0;
font-family: "Segoe UI", sans-serif;
background-color: #000;
color: #fff;
}
#app {
max-width: 600px;
margin: 50px auto;
padding: 0 15px;
}
.tweet-box {
background-color: #1a1a1a;
padding: 15px;
border-radius: 10px;
margin-bottom: 20px;
}
.tweet-box textarea {
width: 100%;
padding: 10px;
font-size: 16px;
border: none;
border-radius: 6px;
resize: none;
background-color: #2b2b2b;
color: white;
box-sizing: border-box; /* ←追加 */
}
.tweet-box button {
margin-top: 10px;
padding: 10px 20px;
background-color: #1d9bf0;
border: none;
color: white;
border-radius: 6px;
cursor: pointer;
}
.tweet {
display: flex;
gap: 10px;
padding: 15px;
background-color: #16181c;
border-radius: 10px;
margin-bottom: 15px;
}
.avatar {
width: 48px;
height: 48px;
background-color: #ccc;
border-radius: 50%;
}
.tweet-content {
flex: 1;
}
.username {
font-weight: bold;
margin-bottom: 5px;
}
.text {
font-size: 15px;
white-space: pre-wrap;
}
CSSbox-sizing: border-box; について
textareaにpaddingやborderをつけたとき、box-sizing: content-box;(デフォルト)のままだと、横幅が100%を超えてズレることがあります。
そこで box-sizing: border-box; を使えば、パディングやボーダー込みで幅を100%に収めることができ、左右のズレを防げます。
Vue.jsで投稿機能を実装
HTMLとCSSで見た目が整ったら、次は**Vue.jsの力を使って、実際に動く「投稿機能」**を実装していきます。
、Vue.jsの魅力のひとつは、少ないコードでインタラクティブなUIを実現できる点です。ここでは、v-model、v-for、そしてVueのmethodsを使って、ユーザーが入力したテキストをリアルタイムで反映・保存・表示する仕組みを作っていきます。
JavaScriptファイル
const { createApp } = Vue;
createApp({
data() {
return {
newTweet: '',
tweets: []
};
},
methods: {
postTweet() {
if (this.newTweet.trim()) {
this.tweets.unshift({
id: Date.now(),
text: this.newTweet
});
this.newTweet = '';
} else {
alert('ツイート内容を入力してください。');
}
}
}
}).mount('#app');
JavaScript解説
✔ v-model による双方向バインディング
HTML側の<textarea>に v-model=”newTweet” を設定することで、
Vueのdata()にあるnewTweetとリアルタイムで値を同期します。
- ユーザーが入力 → newTweetに反映
- newTweetをクリアすると、textareaもクリア
という双方向のやり取りが実現します。
v-forで投稿をループ表示
HTML内のこの部分に注目:
<div class="tweet" v-for="tweet in tweets" :key="tweet.id">
<div class="avatar"></div>
<div class="tweet-content">
<p class="username">@example_user</p>
<p class="text">{{ tweet.text }}</p>
</div>
</div>
HTMLVueのv-forディレクティブを使うことで、tweets配列に入っているすべての投稿を1つずつ表示できます。:keyにはユニークなID(ここではDate.now()で生成)を使うのがベストプラクティスです。
投稿追加メソッド(postTweet())
ユーザーがボタンを押すと、postTweet()が実行されます。
この関数の流れは以下のとおり:
newTweetが空でなければtweets配列の先頭に新しい投稿を追加- テキストエリアをクリア
バリデーションのポイント
空白だけの投稿(例:” “)を防ぐために、trim()を使ってチェックしています:
if (this.newTweet.trim()) {
// 投稿処理
}JavaScriptこういった細かいチェックも、Vueでのフォーム処理には大切なポイントです。
応用ポイント・発展アイデア
今回作成したアプリはVue.jsだけで動くシンプルなローカル投稿アプリですが、ここからさらに発展させていくこともできます。以下にいくつかの拡張アイデアを紹介します。
ローカルストレージ保存
現状ではページをリロードすると投稿が消えてしまいます。
それを防ぐには、localStorageを使って投稿データを保存・読み込みする処理を追加すればOKです。
mounted() {
const saved = localStorage.getItem('tweets');
if (saved) this.tweets = JSON.parse(saved);
},
watch: {
tweets: {
handler(newTweets) {
localStorage.setItem('tweets', JSON.stringify(newTweets));
},
deep: true
}
}
JavaScriptSocket.IOでリアルタイム化
Node.jsとSocket.IOを組み合わせることで、複数のユーザー間でリアルタイム投稿共有も可能になります。
- 投稿が他ユーザーの画面にも即座に反映
- チャット風アプリやABEMA風コメント表示にも応用可能
Vue + Socket.IOの組み合わせは、インタラクティブなアプリの第一歩としておすすめです。
Firebaseなどでバックエンド連携
投稿データをサーバーに保存・取得したい場合は、Firebase(Firestore)やSupabaseなどの**BaaS(Backend as a Service)**を利用すると便利です。
- ログイン認証(Googleアカウントなど)
- 投稿のデータベース保存
- デバイス間の同期も簡単に実現可能
まとめ
Vue.jsを使えば、シンプルなコードで動くアプリを素早く構築することができます。
今回は「自分専用のツイートアプリ」をテーマに、HTML・CSS・Vueだけで構築しました。
今後は以下のような発展も視野に入れると、さらにVueの理解が深まります。
- 投稿部分のコンポーネント化
- Vue Routerでページ分け
- Piniaなどを使った状態管理
- 本格的なAPI連携やログイン機能の実装
まずは手を動かして、小さなアプリを完成させてみるところから始めましょう。
Vueは楽しい!そして、思ったより簡単!
そう感じてもらえたら、この記事は大成功です。

コメント