Vue.js、自分だけの共有できないツイートアプリを作成しよう!

javascript
この記事は約11分で読めます。

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;
}
CSS

box-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>
HTML

Vueのv-forディレクティブを使うことで、tweets配列に入っているすべての投稿を1つずつ表示できます。:keyにはユニークなID(ここではDate.now()で生成)を使うのがベストプラクティスです。

投稿追加メソッド(postTweet())

ユーザーがボタンを押すと、postTweet()が実行されます。

この関数の流れは以下のとおり:

  1. newTweetが空でなければ
  2. tweets配列の先頭に新しい投稿を追加
  3. テキストエリアをクリア

バリデーションのポイント

空白だけの投稿(例:” “)を防ぐために、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
  }
}
JavaScript

Socket.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は楽しい!そして、思ったより簡単!
そう感じてもらえたら、この記事は大成功です。

コメント