難解な JavaScript

(2025-03-06)

JavaScript はとても難解です。それを理解しないとリアルタイムチャットはできないと思います。

コピペで動くのでそのまま使おうとしたのですが、そうすると全然応用がききません。

流れ

まずは、chat.blade.php で

chat.blade.php
<div class="px-4 py-3 bg-gray-200 border-t border-gray-300">
<chat-form v-on:messagesent="addMessage" :user="{{ auth()->user() }}"></chat-form>
</div>
  1. Laravel の Blade テンプレートに<chat-form>コンポーネントが書かれている。
  2. :user="{{ auth()->user() }}" によって、現在のログインユーザーを Vue に渡す。
  3. v-on:messagesent="addMessage" で、messagesent イベントを受け取ったら addMessage() を実行するよう設定。

ChatForm.vue の

ChatForm.vue
function sendMessage(e) {
if (newMessage.value === '') return;
emit("messagesent", {
user: props.user,
content: newMessage.value
});
newMessage.value = "";
}

が呼ばれます。

  1. Blade から渡された user を props として受け取る。
  2. メッセージを入力し、送信ボタンを押すと sendMessage() が実行される。
  3. emit("messagesent", { user: props.user, content: newMessage.value }) によって、親コンポーネント(chat.js)に messagesent イベントを送信。
emit("messagesent", { user: props.user, content: newMessage.value })

という部分で、

messagesent というカスタムイベントを発火(親コンポーネントにデータを渡す)。親コンポーネントとは chat.js のことです。

chat.js
.component('chat-form', ChatForm)
window.Echo.private('chat')
.listen('MessageSent', (e) => {
messages.value.push({
content: e.message.content,
user: e.user
});
});
function addMessage(message) {
messages.value.push(message);
axios.post('/messages', message).then(response => {
});
}
  1. chat.js で<chat-form>を登録し、messagesent イベントをリッスン。
  2. addMessage(message) を実行して、メッセージリストに追加する。
  3. axios.post('/messages', message) によって、サーバーへメッセージを送信。
  4. window.Echo.private('chat').listen('MessageSent', (e) => {...}) により、リアルタイムでメッセージを受信。

以上が chatGPT の説明です。

すべてを chat.js にまとめる

import { createApp, ref, onMounted } from 'vue';
import axios from 'axios';
// Vue アプリの作成
createApp({
setup() {
const messages = ref([]);
const newMessage = ref('');
const user = ref({ id: 1, name: "自分" }); // 仮のユーザー情報
// メッセージ取得
const fetchMessages = () => {
axios.get('/messages').then(response => {
messages.value = response.data.map(msg => ({
content: msg.content,
user: msg.user
}));
});
};
// メッセージ送信
const sendMessage = () => {
if (newMessage.value === '') return;
const message = { user: user.value, content: newMessage.value };
messages.value.push(message);
newMessage.value = '';
axios.post('/messages', message);
};
// Pusher 経由でリアルタイム更新
onMounted(() => {
fetchMessages();
window.Echo.private('chat').listen('MessageSent', (e) => {
messages.value.push({
content: e.message.content,
user: e.user
});
});
});
return {
messages,
newMessage,
user,
sendMessage
};
},
template: `
<div class="container">
<!-- メッセージ一覧 -->
<ul class="list-group mb-3">
<li v-for="message in messages"
:key="message.id"
:class="message.user.id === user.id ? 'text-end' : 'text-start'">
<strong>
<span v-if="message.user.id === user.id">私</span>
<span v-else>{{ message.user.name }}さん</span>
</strong>
<p>{{ message.content }}</p>
</li>
</ul>
<!-- メッセージ入力フォーム -->
<div class="input-group">
<input type="text" class="form-control"
v-model="newMessage" @keydown.enter="sendMessage"
placeholder="メッセージを入力..." />
<button class="btn btn-primary" @click="sendMessage">送信</button>
</div>
</div>
`
}).mount('#app');

コードが長いとわかりにくくなるので、vue ファイルに分離するんでしょうね。

でも、JavaScript って本当に難解です。