채팅방 2개가 있고, 로그인 하면 기본으로 0번방으로 접속됨
채팅은 해당 방에 있는 유저한테만 보이고, 접속한 사용자의 목록중에서
id를 클릭해서 내용 입력 후, 귓속말 버튼을 누르면 해당 유저에게 귓속말 가능
<!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>
</head>
<body>
<div style="display: flex;">
<div class ="content">
<div>귀여운 동물 카톡</div>
<div id = "login">
<p>로그인</p>
<input type="text" id="username">
<button id="loginBtn">접속</button>
</div>
<div id="main">
<select name="" id="rooms">
<option value="0번방">0번방</option>
<option value="1번방">1번방</option>
</select>
<div id="send">
<input type="text" id="msg">
<button id="sendBtn">보내기</button>
</div>
<div id ="send2">
<input type="text" id="msg2">
<button id="sendBtn2">귓속말</button>
</div>
<ul id="messages">
</ul>
</div>
<div id="userAll">
<span>접속한 사용자</span>
<ul id="list">
</ul>
</div>
</div>
</div>
</body>
<script>
window.onload = ()=>{
loginBtn.onclick = ()=>{
login.style.display = "none";
main.style.display = "block";
const name = username.value;
let room = rooms.options[rooms.selectedIndex].value;
const socket = io.connect();
socket.emit("list",room,name);
socket.emit("joinRoom",room,name);
rooms.onchange = function(e){
//이벤트가 일어난 태그
let el = e.target;
console.log("--------el",el.selectedIndex);
// 해당 유저가 room에서 떠남
console.log(room); // 현재방
socket.emit("leaveRoom",room,name);
room = rooms.options[el.selectedIndex].value;
console.log(room); // 바꾼방
socket.emit("joinRoom",room,name);
}
socket.on("list",(room,room1)=>{
list.innerHTML ="";
console.log(room1);
room1.forEach((el)=>{
console.log(el);
})
for (let i = 0; i < room1.length; i++) {
list.innerHTML +=
`<button class="bbtn">${room1[i].name}</button><br>`;
}
let bbtn = document.querySelectorAll(".bbtn");
console.log(bbtn);
bbtn.forEach((el,index)=>{
el.onclick = ()=>{
console.log("클릭됨");
console.log(index);
msg2.value =room1[index].name;
}
})
})
socket.on("joinRoom",(room,name)=>{
messages.innerHTML += `
<li class="join_text">
${name}님이 ${room}에 들어왔음.
</li>
`;
})
socket.on("leaveRoom",(room,name)=>{
messages.innerHTML += `
<li class = "leave_text">
${name}님이 ${room}에서 나갔음.
</li>
`
})
socket.on("chat",(name,msg)=>{
const lii = document.createElement("li");
const textt = `${name} : ${msg}`;
lii.append(textt);
messages.appendChild(lii);
})
sendBtn.onclick= ()=>{
console.log("눌림");
socket.emit("chat",room,name,msg.value);
msg.value ="";
}
sendBtn2.onclick =()=>{
socket.emit("chat2",msg2.value,name,msg.value);
msg.value = "";
}
}
}
</script>
</html>
const express = require("express");
const path = require("path");
const socketio = require("socket.io");
const app = express();
app.set("views",path.join(__dirname,"page"));
app.set("view engine","ejs");
const server = app.listen(8070,()=>{
console.log("server on");
})
app.get('/',(req,res)=>{
res.render("main");
})
let userId=[];
let room1=[];
const io = socketio(server);
// 유저가 접속하면
io.on("connection",(socket)=>{
socket.on("joinRoom",(room,name)=>{
//방에 유저가 접속하면
//join 메서드로 방에 입장 시킨다
//방의 개념
socket.join(room);
//현재 방에 있는 클라이언트에게 이벤트 푸쉬
io.to(room).emit("joinRoom",room,name);
})
socket.on("leaveRoom",(room,name)=>{
//유저가 방에서 나가면
//유저가 방에서 제외되게 해주고
socket.leave(room);
//어느방에서 누가 나갔는지 해당 방에 있는 유저들에게 이벤트 푸쉬
io.to(room).emit("leaveRoom",room,name);
})
// 유저 접속시 배열에 유저의 아이디 추가
userId.push(socket.id);
const socketId = socket.id;
// 방번호랑 , 로그인할 때 이름을 받고
socket.on("list",(room,name)=>{
room1.push({name,socketId,room});
socket.join(room);
// 그 룸에 다가 그사람 이름 표시해야하는데
io.to(room).emit("list",room,room1);
})
socket.on("disconnect",()=>{
userId = userId.filter((value)=> {
return value!=socket.id
});
room1 = room1.filter((value)=> value.socketId!=socket.id)
io.emit("list","",room1);
})
socket.on("chat",(room,name,msg)=>{
io.to(room).emit("chat",name,msg);
})
socket.on("chat2",(id,name,msg)=>{
for (let index = 0; index < room1.length; index++) {
if(id==room1[index].name){
id=room1[index].socketId;
}
}
io.to(id).emit("chat",name,"귓속말"+msg);
})
})
이름 입력 후 접속 버튼을 눌렀을 때
// 🚩 main.ejs
loginBtn.onclick = ()=>{
const name = username.value;
// select 태그는 따로 설정하지않으면 기본 value는 첫번째 옵션으로 들어간다.
let room = rooms.options[rooms.selectedIndex].value;
// 서버에 연결시도
const socket = io.connect();
// 서버의 socket.on 에 emit
socket.emit("list",room,name);
socket.emit("joinRoom",room,name);
}
// 🚩 app.js
// 매개변수 room : 몇번방 인지, name : 입력한 이름
socket.on("list",(room,name)=>{
// room1 빈배열에 객체정보를 푸쉬
room1.push({name,socketId,room});
// join() 메서드를 사용해 소켓을 특정 방에 조인
socket.join(room);
// to() 메서드를 사용해 클라이언트 쪽 socket.on에 emit
io.to(room).emit("list",room,room1);
}
// 동작원리는 같다.
socket.on("joinRoom",(room,name)=>{
socket.join(room);
io.to(room).emit("joinRoom",room,name);
})
// emit 을 했으니 다시 main.ejs 의 socket.on으로
// 🚩 main.ejs
socket.on("list",(room,room1)=>{
list.innerHTML ="";
for (let i = 0; i < room1.length; i++) {
// 옆에 접속한 유저의 목록을 띄움.
list.innerHTML +=
`<button class="bbtn">${room1[i].name}</button><br>`;}
// 접속한 유저의 목록을 띄울 때 button 태그를 달아
// 유저 이름 클릭시 귓속말 input에 클릭한 유저 이름 들어가게끔 설정.
let bbtn = document.querySelectorAll(".bbtn");
bbtn.forEach((el,index)=>{
el.onclick = ()=>{
msg2.value = room1[index].name;
}})})
// 유저가 방에 입장했을때 들어왔다는 text를 띄움.
socket.on("joinRoom",(room,name)=>{
messages.innerHTML += `
<li class="join_text">
${name}님이 ${room}에 들어왔음.
</li>
`;})
채팅 입력후 보내기 버튼을 눌렀을 때
//🚩 main.ejs
sendBtn.onclick= ()=>{
// socket.on("chat")으로 방번호, 이름, 메세지 내용을 emit
socket.emit("chat",room,name,msg.value);
msg.value ="";
}
//🚩 app.js
socket.on("chat",(room,name,msg)=>{
// room 번호에 join 된 유저한테만 emit
io.to(room).emit("chat",name,msg);
})
//🚩 main.ejs
socket.on("chat",(name,msg)=>{
const chatlist = document.createElement("li");
const chatcontent = `${name} : ${msg}`;
chatlist.append(chatcontent);
messages.appendChild(chatlist);
})
채팅 입력후 귓속말 버튼을 눌렀을 때
// 🚩 main.ejs
whisperBtn.onclick =()=>{
// socket.on("chat2") 에 클릭한 유저이름, 내 이름, 메시지 내용을 emit
socket.emit("chat2",msg2.value,name,msg.value);
msg.value = "";
}
//🚩 app.js
socket.on("chat2",(id,name,msg)=>{
// io.to로 특정 유저에게 emit 하려면
//해당 유저의 소켓ID를 사용해야 하기때문에 소켓ID를 추출하는 과정.
for (let index = 0; index < room1.length; index++) {
if(id==room1[index].name){
id=room1[index].socketId;
}
}
io.to(id).emit("chat",name,"귓속말"+msg);
})
// 그 이후 위와같이 main.ejs의 socket.on("chat")이 실행됨.
채팅방을 변경했을 때
rooms.onchange = function(e){
let el = e.target;
// 여기서 room 의 값은 0번방
socket.emit("leaveRoom",room,name);
// room의 값은 el의 selectedIndex 의 값을 저장
// 0번방 or 1번방이 저장됨.
room = rooms.options[el.selectedIndex].value;
// 여기서 room 의 값은 1번방
socket.emit("joinRoom",room,name);
}
이후 emit 을 통해 어떤 유저가 어떤방이 들어오고 나갔는지
출력하는 socket.on 이벤트를 실행.
클라이언트가 소켓 연결을 종료했을 때
// 🚩 app.js
// 내장된 이벤트로 disconnect는 클라이언트가 서버와 연결을 해제할 떄
// 자동으로 발생하는 이벤트
socket.on("disconnect",()=>{
// 클라이언트가 서버에 연결했을 때 userId 라는 빈배열에 소켓ID를 푸쉬했었음.
// 그 푸쉬한 배열에서 지금 연결을 해제한 socket.id 만 제외하고 필터하여 userId 배열 갱신
userId = userId.filter((value)=> {
return value!=socket.id
});
// 접속한 유저의 목록에서도 제외해야하니깐 똑같이 필터
room1 = room1.filter((value)=> value.socketId!=socket.id)
// 연결된 모든 클라이언트에게 메시지 emit
io.emit("list","",room1);
})
// main.ejs의 socket.on("list")로 가서 이벤트 처리됨.