ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 2019-09-11 개발일지
    개발일지 2019. 9. 11. 16:22

    어제 올린 글 검토하는데 움짤이 짤리더라.

    보니까 티스토리에서 업로드 되는 gif 움짤 파일에 대해서 최적화 작업을 진행하는 것 같은데 해당 기능에 문제가 있나보다.

     

    그래서 열받아서 그냥 움짤은 스킵하기로 했다.

     

     

    오늘은 채팅 화면에서 목록 메뉴를 클릭하면 선택한 채팅방으로 입장하는 것을 완성해보자.

    요기임 요기

    엘리먼트나 디자인은 이전 개발일지에서 모두 리뷰했으므로 동적인 기능과 서버 통신을 리뷰합니다.

     

    클라이언트 스크립트 부터 보자.

    /**
     * 채팅방 입장 액션
     * @author Johnny
     */
    roomsEl.forEach(room => {
        room.addEventListener('click', e => {
            // 활성화 태그 제거 & 메뉴 클릭 방지 해제
            document.querySelectorAll('.room-el.active').forEach(room => {
                room.classList.remove('active');
                room.style.pointerEvents = 'auto';
            });
    
            if (roomId !== room.dataset.id)
            {
                console.log(`roomId: ${roomId} / room.dataset.id: ${room.dataset.id}`);
                roomId = room.dataset.id;
            }
            room.classList.add('active');
            room.style.pointerEvents = 'none';
    
            // 새로운 방으로 이동 시 채팅로그 클리어
            chatLog.innerHTML = '';
    
            // 참여자 목록에 나를 추가
            chatHeader.innerHTML = room.innerHTML;
    
            /**
             * 채팅방 입장 요청 이벤트 발생
             * @author Johnny
             * @param roomId 입장 할 채팅방 번호
             */
            socket.emit('join room', {
                roomId
            });
        });
    });
    1. 목록 메뉴를 클릭했을 때 이벤트를 발생시키기 위해 반복문을 통해서 각각 엘리먼트 요소에 클릭 이벤트 리스너를 바인딩한다.
      1. 클릭을 하면 클릭한 채팅방 태그에 활성화 클래스를 추가한다.
      2. roomId에 현재 채팅방 아이디를 저장한다.
      3. 소켓으로 join room 이벤트를 발생시키고 인자로 접속한 채팅방 번호를 전달한다.

     

    클라이언트에서 이벤트를 발생시켰으니 서버에서 캐치해보자.

    /**
     * 채팅방 접속 이벤트
     * @author Johnny
     * @param roomData.roomId 접속한 채팅방 아이디
     */
    socket.on('join room', roomData => {
        const userId = getUserBySocketId(socket.id);
        const prevRoomId = onlineUsers[userId].roomId;
        const nextRoomId = roomData.roomId;
    
        socket.leave(`room${prevRoomId}`);
        socket.join(`room${nextRoomId}`);
    
        onlineUsers[userId].roomId = nextRoomId;
    
        updateUserList(prevRoomId, nextRoomId, userId);
    });
    
    
    /**
     * 소켓 아이디로 사용자 정보 구하기
     * @author Johnny
     * @param socketId 소켓 아이디
     */
    function getUserBySocketId(socketId: string): string {
        console.log('>>>>> getUserBySocketId() onlineUsers : ', onlineUsers);
        console.log('>>>>> getUserBySocketId() socketId : ', socketId);
        const userId = Object.keys(onlineUsers).find(key => onlineUsers[key].socketId === socketId);
        console.log('>>>>> getUserBySocketId() id : ', userId);
        return userId ? userId : '';
    }
    1. join room 이벤트를 캐치한다.
      1. 소켓 아이디로 사용자 아이디를 찾는다.
      2. onlineUsers객체에서 사용자 아이디로 검색하여 채팅방 아이디를 가져온다. (내가 떠나려는 채팅방)
      3. 인자로 전달 된 roomData에서 roomId를 가져온다. (내가 새로 들어가려는 채팅방)
      4. socket.leave()로 사용자를 현재 채팅방에서 나가게 한다.
      5. socket.join()으로 사용자를 새로운 채팅방에 접속시킨다.
      6. onlineUsers객체에 roomId 정보를 새롭게 접속한 채팅방 아이디로 갱신해준다.
      7. 채팅 접속자 목록을 갱신한다.

     

     

     

    이제 서버를 키고 작동하는지 확인해봅시다.

     

    좌측의 목록에서 채팅방을 변경하면 클릭이 되는 것을 볼 수 있다.

    목록에서 새로운 채팅방을 클릭하면 클릭한 채팅방에 하이라이트가 생기고 새로운 채팅방으로 접속된다.

     

     

    채팅방에 접속이 잘 되니 이제 메시지 발송을 해봅시다.

     

    클라이언트 스크립트를 작성하자.

    /**
     * 메시지 발송 액션
     * @author Johnny
     */
    sendMessageSubmit.addEventListener('click', e => {
        e.preventDefault();
        const message = document.querySelector('#message');
    
        console.log(message.value);
        if (message.value) {
            const messageData = { roomId, message: message.value };
                    
            socket.emit('send message', messageData);
    
            message.value = '';
            message.focus();
        }
    });
    1. 보내기 버튼에 대한 클릭 이벤트 리스너를 바인딩한다.
      1. 메시지 입력 input 태그에 내용이 있는지 검증한다. 
        1. 현재 채팅방 번호와 메시지 내용을 담아서 'send message' 이벤트를 발생시킨다.
        2. 메시지 입력 input 태그를 초기화하고 focus를 맞춘다.

     

     

    이제 서버측에서 send message 이벤트를 캐치하자.

    /**
     * 메시지 발송 이벤트
     * @author Johnny
     * @param messageData.roomId 접속한 채팅방 아이디
     * @param messageData.message 메시지 내용
     */
    socket.on('send message', messageData => {
        console.log('messageData :', messageData);
    
        const { roomId, message } = messageData;
        const socketId = socket.id;
    
        chat2Channel.in(`room${roomId}`).emit('new message', {
            name: getUserBySocketId(socketId),
            socketId,
            message
        });
    });
    1. send message에 대한 이벤트를 캐치한다.
      1. chat2 채널의 특정 채팅방에 있는 모두에게 사용자 닉네임과 메시지 내용을 담아 'new message' 이벤트를 발생시킨다. (다른 사용자들에게 메시지 내용을 공유하는 작업)

     

     

    그럼 다시 클라이언트 스크립트로 돌아가서 신규 메시지 이벤트를 캐치하자.

    /**
     * 신규 메시지 받기 이벤트
     * @author Johnny
     * @param messageData.socketId 채널 아이디
     * @param messageData.message 메시지 내용
     * @param messageData.name 사용자 아이디
     */
    socket.on('new message', messageData => {
        const { socketId: getSocketId, message, name } = messageData;
        const messageDivHTML = document.createElement('div');
    
        if (socketId === getSocketId) {
            messageDivHTML.classList.add('my-msg', 'msg-el');
            messageDivHTML.innerHTML = `<span class='msg'>${message}</span>`;
        } else {
            messageDivHTML.classList.add('other-msg', 'msg-el');
            messageDivHTML.innerHTML = `<span class='other-name'>${name}</span>
            <span class='msg'>${message}</span>`;
        }
                
        chatLog.append(messageDivHTML);
        chatLog.scrollTop = chatLog.scrollHeight; // 스크롤 발생 시 맨 밑으로 이동
    });
    1. new message 이벤트를 캐치한다.
      1. 소켓 아이디가 같으면 내가 작성한 메시지니까 msg 클래스를 붙여서 태그를 만든다.
      2. 소켓 아이디가 다르면 다른 사람이 작성한 메시지니까 other-name 클래스를 붙여서 태그를 만든다.
      3. 신규 메시지 엘리먼트가 쌓여서 스크롤이 생성되면 맨 밑으로 이동하여 최신 메시지가 보여지도록 한다.

     

     

    이제 채팅을 해보자.

     

    내가 작성한 메시지는 파란색으로 표현된다.

    상대방의 메시지는 회색톤으로 표현되고 내가 보낸 메시지는 파란톤으로 표현된다.

     

    상대와 나는 서로 메시지를 잘 주고 받는다.

    '개발일지' 카테고리의 다른 글

    2019-09-17 개발일지  (0) 2019.09.17
    2019-09-16 개발일지  (0) 2019.09.16
    2019-09-10 개발일지  (0) 2019.09.10
    2019-09-09 개발일지  (0) 2019.09.09
    2019-09-06 개발일지  (0) 2019.09.06
Designed by Tistory.