본문 바로가기
Develop/Zoom만들기

ZOOM만들기 10. 채팅룸 완성하기

by 보보트레인 2023. 9. 1.

1. 닉네임 추가하기

1-1) home.pug 수정하기

닉네임 입력 폼 하나 추가해야함.

doctype html

html(lang="en")
    head
        meta(charset="UTF-8")
        meta(http-equiv="X-UA-Compatible", content="IE=edge")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Zoom
        //MVP.css는 우리가 태그에 class나 id같은 특성을 추가하지 않아도 자동으로 스타일을 적용해주는 라이브러리다.
        link(rel="stylesheet", href="https://unpkg.com/mvp.css")
    body
        //h1 It works!
        header
            h1 Zoom
        main
            div#welcome
                form
                    input(placeholder="room name", required, type="text")
                    button Enter Room
            div#room
                h3
                ul
                form#name
                    input(placeholder="nickname", required, type="text")
                    button Save
                form#msg
                    input(placeholder="message", required, type="text")
                    button Send
        script(src="/socket.io/socket.io.js")
        script(src="/public/js/app.js")


<결과화면>

1-2) app.js 수정하기

추가한 폼을 처리하기 위해 수정

const socket = io();

const welcome = document.getElementById("welcome");
const form = welcome.querySelector("form");
const room = document.getElementById("room");

room.hidden = true;

let roomName;

function addMessage(message){
    //메시지 받아서 저장
    const ul = room.querySelector("ul");
    //li 생성
    const li = document.createElement("li");
    //li에 저장해둔 메시지 담음
    li.innerText = message;
    //ul에 가져다 붙힘
    ul.appendChild(li);
}

function handleMessageSubmit(event){
    event.preventDefault();
    const input = room.querySelector("#msg input");
    const value = input.value;
    socket.emit("new_message", value, roomName, () => {
        addMessage(`You: ${value}`);
    });
    input.value = "";
}

function handleNicknameSubmit(event){
    event.preventDefault();
    const input = room,querySelector("#name input");
    const value = input.value;
    socket.emit("nickname", value);
    input.value = "";
}

function showRoom(){
    welcome.hidden = true;
    room.hidden = false;
    const h3 = room.querySelector("h3");
    h3.innerText  =`Room ${roomName}`;
    const msgform = room.querySelector("#msg");
    const nameForm = room.querySelector("#name");
    msgform.addEventListener("submit", handleMessageSubmit);
    nameform.addEventListener("submit", handleNicknameSubmit);
}

function handleRoomSubmit(event){
    event.preventDefault();
    const input = form.querySelector("input");
    socket.emit("enter_room", input.value, showRoom);
    roomName = input.value;
    input.value = "";
}

form.addEventListener("submit", handleRoomSubmit);
 
//서버로부터 welcome받으면 메시지 날리도록 체킹
socket.on("welcome", (userNickname) => {
    addMessage(`${userNickname} arrived!`);
});

socket.on("bye", (userNickname) => {
    addMessage(`${userNickname} left!`);
});

socket.on("new_message", (msg) => {
    addMessage(msg);
});

showRoom은 사용자가 채팅룸에 접속하면 동작하는 함수. 

이 함수에서 메시지 폼과 닉네임 폼에 대한 이벤트 처리를 모두 등록하면 됨.

서버에서 userNickname을 돌려받아 addMessage로 띄울 수 있도록 미리 세팅

 

1-3) server.js 수정하기

닉네임을 입력할 때 발생하는 nickname 이벤트를 서버에서 처리할 수 있게 해줘야함.

import http from 'http';
import SocketIO from "socket.io";
import express from 'express';

const app = express();

app.set("view engine", "pug");
//dirname은 Node.js기본 전역변수로, 현재 실행되는 폴더의 경로를 의미
app.set("views", __dirname + "/views");
app.use("/public", express.static(__dirname + "/public"));

// '/'를 받으면 home으로 가게 설정
app.get("/", (req, res) => res.render("home"));
//만약홈이 아닌 다른 주소로 get요청을 보내더라도 홈으로 리다이렉션하게 예외처리함
app.get("/*", (req, res) => res.redirect("/"));

const httpServer = http.createServer(app);
const wsServer = SocketIO(httpServer);

wsServer.on("connection", (socket) => {
    //닉네임이 입력되기 전까지는 익명으로 표시
    socket["nickname"] = "Anon";
    socket.on("enter_room", (roomName,done) => {

        //브라우저가 요청한 콜백을 의미 - showRoom()을 의미.
        done();
       //소켓 룸 생성 및 접속 - 해당 roomName으로 조인시킴
       socket.join(roomName);
       //to메서드
       socket.to(roomName).emit("welcome", socket.nickname);
    });
    socket.on("disconnecting", () =>{
        socket.rooms.forEach(room =>
             socket.to(room).emit("bye", socket.nickname));
    });
    socket.on("new_message", (msg, room, done) =>{
        socket.to(room).emit("new_message", `${socket.nickname}: ${msg}`);
        done();
    })
    socket.on("nickname", (nickname) => (socket["nickname"] = nickname));
});

const handleListen = () => console.log("Listening on http://localhost:3000");
httpServer.listen(3000,handleListen);

채팅룸에 입장하거나 퇴장할 때마다 이벤트를 발생시켜 닉네임을 전달하게 했고, 메시지를 입력했을 때는 누가 입력한 메시지인지 표시되도록 메시지에 닉네임을 함께 전달함.

 

<결과 확인>

1이 접속해 있는 bobo's room 에 2가 접속했을 때, 

1이 닉네임을 bobo로 설정 후 채팅 쳤을 때, 1과 2의 화면

1 화면
2 화면

닉네임이 잘 붙어서 출력된다.

반응형