除了共用的频道外,当不同使用者进入时,希望能够出现一个很阳春的不同使用者的聊天频道,并进行私人讯息。
而这一章首要解决的,便是不同使用者进入时,自动更新建立频道。
第一步,记录登入的使用者名称到 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,
};
<<: [Day 10] Reactive Programming - Reactor (generate & create)
>>: 用资料结构看 evernote - 修改前 - DAY 10
Hello, 各位 iT邦帮忙 的粉丝们大家好~~~ 本篇是 Re: 从零开始用 Xamarin 技...
题号:59 标题:Spiral Matrix II 难度:Medium Given a positi...
工具有许多种,不过随着专案大小与需求不同,搭配适合的实作方式才能达到最佳效益,常见的 Google ...
什麽是封装 In object-oriented programming (OOP), encaps...
在写程序的过程, 多多少少会遇到需要复杂处理的状况, Go的优点是很多使用情境已经有前人帮忙整理成套...