상세 컨텐츠

본문 제목

[Node JS] Socket IO를 이용한 웹 채팅 서비스 구현하기

IT/Javascript

by SINAFLA 2021. 4. 11. 20:24

본문

반응형

 

개발 환경

1. 에디터 : Visual Studio Code를 이용

2. node 버전 : 14.16

 

 

npm 으로 설치할 것

  • express
  • socketIO
  • moment : 시간을 불러올 때 사용함

 

파일 구조

 

소스

app.js

더보기
const express = require('express');
const http = require('http');
const app = express();
const path = require('path');
const server = http.createServer(app);
const socketIO = require('socket.io');
const moment = require('moment');

const io = socketIO(server);

app.use(express.static(path.join(__dirname, "src")));

const PORT = process.env.PORT || 5000; 

io.on ("connection", (socket) => {
    socket.on('chatting', (data) => {
        const {name, msg} = data;
        io.emit('chatting', {
            name,
            msg,
            time: moment(new Date()).format("hh:mm A")
        });
    });
});

server.listen(PORT, () => console.log(`server is running : ${PORT}`));

 

 

index.html

더보기
<!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>Document</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <div class="wrapper">
        <div class="user-container">
            <label for="nickname">대화명</label>
            <input type="text" id="nickname">
        </div>
        <div class="display-container">
            <ul class="chatting-list">
            
            </ul>
        </div>
        <div class="input-container">
            <span>
                <input type="text" class="chatting-input">
                <button class="send-button">전송</button>
            </span>
        </div>
    </div>

    <script src="/socket.io/socket.io.js"></script>
    <script src="js/chat.js"></script>
</body>
</html>

 

 

chat.js

더보기
"use strict"

const socket = io();

const nickname = document.querySelector("#nickname");
const chatList = document.querySelector(".chatting-list");
const chatInput = document.querySelector(".chatting-input");
const sendButton = document.querySelector(".send-button");
const displayContainer = document.querySelector(".display-container");

chatInput.addEventListener("keypress", (event) => {
    if(event.keyCode === 13) {
        send();
    }
});

function send() {
    const param = {
        name : nickname.value,
        msg: chatInput.value
    };

    socket.emit("chatting", param);
}

sendButton.addEventListener("click", send());

socket.on('chatting', (data) => {
    const {name, msg, time} = data;
    const  item = new LiModel(name, msg, time);
    item.makeLi();
    displayContainer.scrollTo(0, displayContainer.scrollHeight);
});

function LiModel(name, msg, time) {
    this.name = name;
    this.msg = msg;
    this.time = time;

    this.makeLi = () => {
        console.log(`nickname: ${nickname.value} / name: ${this.name}`);
        const li = document.createElement("li");
        li.classList.add(nickname.value === this.name ? "sent" : "received");
        const dom = `
            <span class="profile">
              <span class="user">${this.name}</span>
              <img class="image" src="https://placeimg.com/50/50/any" alt="any">
            </span>
            <span class="message">${this.msg}</span>
            <span class=time>${this.time}</span>
        `;

        li.innerHTML = dom;
        chatList.appendChild(li);
    };
}

 

 

style.css

더보기
* {
    margin: 0;
    padding: 0;
}

html, body {
    height: 100%;
}

.wrapper {
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: column; 
  overflow: hidden;
}

.user-container {
    background: #a9bdce;
    flex: 1;
    display: flex;
    justify-content: flex-start;
    align-items: center;
    padding: 0.5rem;
}

.user-container label {
    font-size: 14px;
    margin-right: 1rem;
}

.user-container input {
    border-radius: 3px;
    border: none;
    height: 100%;
}

.display-container {
    flex: 12;
    background: #b2c7d9;
    overflow-y: scroll;
}

.input-container {
    flex: 1;
    display: flex;
    justify-content: stretch;
    align-items: center;
}

.input-container span {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    padding: 0.3rem;
    width: 100%;
    height: 100%;
}

.chatting-input {
    font-size: 12px;
    height: 100%;
    flex: 8;
    border: none;
}

.send-button {
    flex: 1;
    background: #ffeb33;
    border: none;
    height: 100%;
    border-radius: 3px;
}

.chatting-list li { 
    width: 90%;
    padding: 0.3rem;
    display: flex;
    justify-content: flex-start;
    align-items: flex-end;
    margin-top: 0.5rem;
}

.profile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex: 1;
}

.profile .user {
    font-size: 10px;
    margin-bottom: 0.2rem;
}

.profile .image {
    border-radius: 50%;
    object-fit: cover;
    width: 50px;
    height: 50px;
}

.message {
    border-radius: 5px;
    padding: 0.4rem;
    font-size: 12px;
    margin: 0 5px;
    flex: 7;
}

.time {
    font-size: 10px;
    margin: 0 5px;

}

.sent {
    flex-direction: row-reverse;
    float: right;
}

.sent .message {
    background: #ffeb33;
}

.received .message{
    background: #fff;
}

 

 

실행 화면

반응형

댓글 영역