除了共用的頻道外,當不同使用者進入時,希望能夠出現一個很陽春的不同使用者的聊天頻道,並進行私人訊息。
而這一章首要解決的,便是不同使用者進入時,自動更新建立頻道。
第一步,記錄登入的使用者名稱到 server 端,所以需要先到中介的 handler.js 轉發訊息。透過 register-new-user
這組 socket 和 server-side 傳輸資料。
另外補充,當使用者登入啟動連線後,連線 socket 的 id 也會被保存 store.js 中,方便隨時可以使用。
// handler.js
import store from '../store.js';
const connectSocketIoServer = () => {
// ...
socket.on('connect', () => {
store.setSocketId(socket.id);
registerActiveSession();
});
};
const registerActiveSession = () => {
const userData = {
username: store.getUserName(),
};
socket.emit('register-new-user', userData);
};
預先保留狀態使用的 function。
// store.js
let socketId = null;
let activeChatGroup = [];
const getSocketId = () => socketId;
const setSocketId = (id) => (socketId = id);
const getActiveChatGroup = () => activeChatGroup;
const setActiveChatGroup = (chatGroup) => (activeChatGroup = chatGroup);
export default {
// ...
getSocketId,
setSocketId,
getActiveChatGroup,
setActiveChatGroup,
};
當 server-side 透過監聽拿到資料後,可以組出一個物件,包含使用 socket.id
當作唯一值的 key,以及 username。每登入一個使用者,就建立一組物件,並將這些物件透過其餘的方式,push 到外層宣告的陣列 connectPeers
,最後再經 boardcastConnectedPeers()
將陣列作為參數轉發回 handler.js。
// server.js
let connectPeers = [];
io.on('connection', (socket) => {
// ...
socket.on('register-new-user', (userData) => {
const { username } = userData;
const newPeer = {
username,
socketId: socket.id,
};
// use spread copy
connectPeers = [...connectPeers, newPeer];
boardcastConnectedPeers();
});
});
const boardcastConnectedPeers = () => {
const data = {
connectPeers,
};
io.emit('active-peers', data);
};
handler.js 拿到資料後,會去 client-side 呼叫 updateActiveChatGroup()
,並將資料傳輸過去,準備進行 render。
client-side 拿到傳輸過來的資料後進行拆解,首先去 store 調出資料,和 server-side 傳輸過來的資料進行比對,剃除重複的使用者,同時呼叫 element.js 中,用於動態 render HTML 的 getChatList()
,將資料作為參數傳入,方便 render 時作為變數使用。
最後將篩選過的物件,同樣透過其餘的方式,push 到 stroe 內保存的陣列,讓下一次使用者登入觸發時,可以再次使用。
const updateActiveChatGroup = (data) => {
const { connectPeers } = data;
const userSocketId = store.getSocketId();
const activeChatGroups = store.getActiveChatGroup();
connectPeers.forEach((peer) => {
const isRepeat = activeChatGroups.find((node) => {
return peer.socketId === node.socketId;
});
if (!isRepeat && peer.socketId !== userSocketId) {
createNewUserChatGroup(peer);
}
});
};
const createNewUserChatGroup = (peer) => {
const chatTitle = peer.username;
const messageContainerID = `${peer.socketId}-message`;
const messageInputID = `${peer.socketId}-input`;
const chatContainerID = peer.socketId;
const data = {
chatTitle,
messageContainerID,
messageInputID,
chatContainerID,
};
const chatGroup = element.getChatList(data);
const chatList = document.querySelector('.chat-list');
chatList.appendChild(chatGroup);
// push new user to chat group
const activeChatGroup = store.getActiveChatGroup();
const newActiveChatGroup = [...activeChatGroup, peer];
store.setActiveChatGroup(newActiveChatGroup);
};
export default {
// ...
updateActiveChatGroup,
};