app.js
const e = require("express");
const path = require("path");
const socketIo = require("socket.io");
const app = e();
app.set("views", path.join(__dirname, "page"));
app.set("view engine", "ejs");
app.use(e.urlencoded({ extended: false }));
const server = app.listen(8080, () => {
console.log("gogo");
});
app.get("/", (req, res) => {
res.render("main");
});
let userId = [];
let roomUser = [];
const io = socketIo(server);
io.sockets.on("connection", (socket) => {
userId.push(socket.id);
console.log(userId);
socket.on("joinRoom", (room, name) => {
socket.join(room);
io.to(room).emit("joinRoom", room, name, socket.id);
});
socket.on("leaveRoom", (room, name) => {
socket.leave(room);
io.to(room).emit("leaveRoom", room, name);
});
socket.on("disconnect", () => {
userId = userId.filter((a) => {
return a != socket.id;
});
console.log("현재 접속중인 유저 id", userId);
});
socket.on("chat", (room, name, msg) => {
io.to(room).emit("chat", name, msg);
});
socket.on("chat2", (id, name, msg) => {
io.to(id).emit("chat", name, "귓속말:" + msg);
});
socket.on("addToTab", (num, room, name) => {
if (roomUser[num] == undefined) {
roomUser[num] = [{ name, id: socket.id }];
} else {
roomUser[num].push({ name, id: socket.id });
}
io.to(room).emit("addToTab", roomUser, num);
});
socket.on("subTab", (num, name,room) => {
roomUser[num] = roomUser[num].filter((a) => {
return a.name != name;
});
io.to(room).emit('subTab',roomUser,num);
});
});
- joinRoom이벤트가 실행되면 socket에 join으로 room을 매개변수로 전달한다.
- 이렇게 하면 to로 해당 room으로 emit을 실행 할 수 있다.
- 즉, room은 단톡방 같은 개념이다
- roomUser는 해당 톡방의 유저목록이다.
- 프론트에서는 5개의 창이 있을 때(유저도 5명), 변수가 공유되지 않는다. 그러므로 서버단에서 로직을 처리하자
- addToTab과subToTab으로 roomUser 배열을 조정하여 해당하는 톡방에 보낸다.
main.ejs<!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>
<script src="/socket.io/socket.io.js"></script>
<style>
body {
position: relative;
height: 100vh;
list-style: none;
}
.content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 500px;
height: 500px;
border: 1px solid;
}
#send {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
border: 1px solid;
box-sizing: border-box;
display: flex;
}
#send #msg {
border: 0;
box-sizing: border-box;
padding: 10px;
width: 85%;
}
#send #sendBtn {
background-color: skyblue;
border: none;
box-sizing: border-box;
padding: 10px;
width: 15%;
cursor: pointer;
z-index: 10;
}
#message {
margin: 0;
padding: 0;
}
#login {
width: 300px;
height: 300px;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.join_text {
background-color: gray;
list-style: none;
}
.leave_text {
background-color: greenyellow;
border: 1px solid skyblue;
list-style: none;
}
#main {
display: none;
}
.tab {
width: 200px;
height: 600px;
border: 1px solid;
position: absolute;
right: 0;
}
.tab li {
list-style: none;
left: 0;
margin: 5px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="content">
<div>귀여운 동물 카톡</div>
<div id="login">
<p>login</p>
<input type="text" id="username" />
<button id="loginBtn">connect</button>
</div>
<div id="main">
<select name="" id="rooms">
<option value="cat">고양이 방</option>
<option value="dog">강아지 방</option>
</select>
<div id="send">
<input type="text" id="msg" />
<button id="sendBtn">send</button>
</div>
<div id="send2">
<input type="text" id="msg2" />
<button id="sendBtn2">indivisual message</button>
</div>
<ul id="message"></ul>
</div>
</div>
<div class="tab">
<ul class="user-list"></ul>
</div>
</body>
<script>
window.onload = () => {
let userId = [];
loginBtn.onclick = () => {
login.style.display = "none";
main.style.display = "block";
const name = username.value;
console.log(rooms.options);
console.log(rooms.selectedIndex);
let room = rooms.options[rooms.selectedIndex].value;
let lastRoom = 0;
const socket = io.connect();
socket.emit("joinRoom", room, name);
rooms.onchange = (e) => {
let el = e.target;
console.log(el.selectedIndex);
socket.emit("leaveRoom", room, name);
socket.emit("subTab", lastRoom, name, room);
room = rooms.options[rooms.selectedIndex].value;
lastRoom = rooms.options[rooms.selectedIndex].value;
socket.emit("joinRoom", room, name);
};
socket.on("chat", (name, msg) => {
message.innerHTML += `
<li >
${name}:${msg}
</li>
`;
});
socket.on("joinRoom", (room, _name, id) => {
message.innerHTML += `
<li class='join_text'>
${_name}님이 ${room}에 들어왔음
</li>
`;
console.log("몇 번?");
if (name == _name)
socket.emit("addToTab", rooms.selectedIndex, room, name);
});
socket.on("addToTab", (roomUser, room) => {
console.log(roomUser, "추가된 유저");
console.log(room);
document.querySelector(".user-list").innerHTML = "";
roomUser[room].forEach((a) => {
console.log(a.id, "아이디");
document.querySelector(".user-list").innerHTML += `
<li id=${a.id}>
이름은 ${a.name},아이디: ${a.id}
</li>
`;
});
setTimeout(() => {
roomUser[room].forEach((a) => {
document
.querySelector(`#${a.id}`)
.addEventListener("click", () => {
msg2.value = a.id;
msg2.placeholer = a.id;
console.log(msg2.value, "asd");
});
}, 200);
});
});
socket.on("subTab", (roomUser, room) => {
roomUser[room].forEach((a) => {
document.querySelector(".user-list").innerHTML = "";
document.querySelector(".user-list").innerHTML += `
<li id=${a.id}>
이름은 ${a.name},아이디: ${a.id}
</li>
`;
});
});
socket.on("leaveRoom", (room, name) => {
message.innerHTML += `
<li class='leave_text'>
${name}님이 ${room}에서 나갔습니다.
</li>
`;
});
sendBtn.onclick = function () {
socket.emit("chat", room, name, msg.value);
msg.value = "";
};
sendBtn2.onclick = function () {
socket.emit("chat2", msg2.value, name, msg.value);
msg2.value = "";
};
};
};
</script>
</html>
- joinRoom 으로 유저가 join할 때 현재 유저 목록(tab)에 유저를 추가한다.
- 이 때, a,b,c유저가 있을 때 c유저가 들어가도 a,b 유저의 joinRoom또한 실행되므로 이를 방지하기위해
socket의 이름과 현재 브라우저의 이름이 같을 때만 addToTab을 emit으로 주게 만들었다.
글 잘 봤습니다, 많은 도움이 되었습니다.