Full Stack 2 دقيقة للقراءة 942 مشاهدات

كيفية بناء تطبيق محادثة مع Laravel وVue.js

أنشئ تطبيق محادثة فوري باستخدام Laravel وVue.js وWebSockets مع حفظ الرسائل.

Chat application

الخلفية: إعداد Laravel

نموذج الرسالة والترحيل

Schema::create('messages', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained();
    $table->foreignId('conversation_id')->constrained();
    $table->text('body');
    $table->timestamps();
});

حدث الرسالة

class MessageSent implements ShouldBroadcast
{
    public function __construct(
        public Message $message
    ) {}

    public function broadcastOn(): Channel
    {
        return new PrivateChannel(
            "conversation.{$this->message->conversation_id}"
        );
    }

    public function broadcastWith(): array
    {
        return [
            'message' => [
                'id' => $this->message->id,
                'body' => $this->message->body,
                'user' => $this->message->user->only(['id', 'name']),
                'created_at' => $this->message->created_at,
            ],
        ];
    }
}

متحكّم إرسال الرسالة

public function store(Request $request, Conversation $conversation)
{
    $message = $conversation->messages()->create([
        'user_id' => auth()->id(),
        'body' => $request->body,
    ]);

    broadcast(new MessageSent($message))->toOthers();

    return response()->json($message->load('user'));
}

الواجهة الأمامية: مكوّن Vue.js

<template>
    <div class="chat-container">
        <div class="messages" ref="messagesContainer">
            <div
                v-for="message in messages"
                :key="message.id"
                :class="['message', { 'own': message.user.id === userId }]"
            >
                <strong>{{ message.user.name }}</strong>
                <p>{{ message.body }}</p>
            </div>
        </div>

        <form @submit.prevent="sendMessage">
            <input v-model="newMessage" placeholder="Type a message..." />
            <button type="submit">Send</button>
        </form>
    </div>
</template>

<script setup>
import { ref, onMounted, nextTick } from 'vue';
import Echo from 'laravel-echo';

const props = defineProps(['conversationId', 'userId']);
const messages = ref([]);
const newMessage = ref('');
const messagesContainer = ref(null);

onMounted(async () => {
    // Load existing messages
    const response = await fetch(`/api/conversations/${props.conversationId}/messages`);
    messages.value = await response.json();

    // Listen for new messages
    window.Echo.private(`conversation.${props.conversationId}`)
        .listen('MessageSent', (e) => {
            messages.value.push(e.message);
            scrollToBottom();
        });
});

const sendMessage = async () => {
    if (!newMessage.value.trim()) return;

    const response = await fetch(`/api/conversations/${props.conversationId}/messages`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ body: newMessage.value }),
    });

    const message = await response.json();
    messages.value.push(message);
    newMessage.value = '';
    scrollToBottom();
};

const scrollToBottom = () => {
    nextTick(() => {
        messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
    });
};
</script>
مشاركة هذه المقالة:
ES
كتبه

Edrees Salih

مهندس برمجيات متكامل يتمتع بخبرة 9 سنوات. شغوف ببناء حلول قابلة للتطوير ومشاركة المعرفة مع مجتمع المطورين.

عرض الملف الشخصي

التعليقات (0)

اترك تعليقًا

لن يتم نشر بريدك الإلكتروني.

لا توجد تعليقات بعد. كن أول من يشارك أفكاره!

مقالات ذات صلة

مقالات ذات صلة

هل تحتاج مساعدة في مشروعك؟

احجز استشارة مجانية لمدة 30 دقيقة لمناقشة تحدياتك التقنية واستكشاف الحلول معًا.