阿里云虛擬主機做2個網(wǎng)站下拉關(guān)鍵詞排名
一、前言
上一篇文章介紹了websocket的詳細(xì)用法與工具類的封裝,本篇就基于websocket搭建一個簡易實時的聊天室。
在本篇開始之前也可以去回顧一下websocket詳細(xì)用法:WebSocket詳解與封裝工具類
二、基于node搭建后臺websocket服務(wù)
首先確認(rèn)本機電腦中是否安裝node,可以通過cmd打開命令窗口運行node -v
查看node版本;
- 建議創(chuàng)建一個空項目:
npm init
- 一路回車就行,然后就得到了一個package.json的配置文件;安裝
ws
模塊
npm i ws
- 新建app.js文件,源碼如下:
const WebSocket = require('ws');
// 隨機姓名
const names = ['趙', '錢', '孫', '李', '周', '吳', '鄭', '王', '馮', '陳', '褚', '衛(wèi)', '蔣', '沈', '韓', '楊', '朱', '秦', '尤', '許', '何','呂', '施', '張', '孔', '曹', '嚴(yán)', '華', '金', '魏', '陶', '姜', '戚', '謝', '鄒', '喻', '柏', '水', '竇', '章', '云', '蘇', '潘', '葛','奚', '范', '彭', '郎', '魯', '韋', '昌', '馬', '苗', '鳳', '花', '方', '俞', '任', '袁', '柳', '酆', '鮑', '史', '唐', '費', '廉', '岑','薛', '雷', '賀', '倪', '湯', '滕', '殷', '羅', '畢', '郝', '鄔', '安', '常', '樂', '于', '時', '傅', '皮', '卞', '齊', '康', '伍', '余','元', '卜', '顧', '孟', '平', '黃', '和', '穆', '蕭', '尹'
];
// 獲取隨便昵稱
const getRandom = (min, max) => {return Math.floor(Math.random() * (min - max) + max)
};
// 創(chuàng)建 WebSocket 服務(wù)器實例
const wss = new WebSocket.Server({port: 8080
});
// 監(jiān)聽連接事件
wss.on('connection', function(socket) {console.log('新連接');const randomIndex = getRandom(0, names.length - 1);socket.nickname = names.splice(randomIndex, 1)[0];sendMessageToClient( '連接成功!進(jìn)入聊天室!');// 監(jiān)聽接收消息事件socket.on('message', function(message) {sendMessageToClient(message);});// 監(jiān)聽接收消息事件socket.on('close', function() {// 廣播消息給所有客戶端wss.clients.forEach(function each(client) {if (client.readyState === WebSocket.OPEN) {client.send(JSON.stringify({nickname: socket.nickname,msg: '退出聊天室!',}));}});});// 監(jiān)聽接收消息事件socket.on('error', function() {// 廣播消息給所有客戶端wss.clients.forEach(function each(client) {if (client.readyState === WebSocket.OPEN) {client.send(JSON.stringify({nickname: socket.nickname,msg: '網(wǎng)絡(luò)不佳,連接失敗 !',}));}});});// 發(fā)送消息到客戶端function sendMessageToClient(message) {let targetMsg = message instanceof Buffer ? message.toString() : message;// 廣播消息給所有客戶端wss.clients.forEach(function each(client) {if (client.readyState === WebSocket.OPEN) {client.send(JSON.stringify({nickname: socket.nickname,msg: targetMsg,}));}});}
});
- 最后啟動node服務(wù):
node app.js
;
三、前端構(gòu)建聊天室
3.1 確定功能點
- 會話框中展示聊天內(nèi)容;
- 輸入框與發(fā)送按鈕發(fā)送消息內(nèi)容;
- 連接websocket,監(jiān)聽實時消息展示到界面中;
3.2 界面結(jié)構(gòu)搭建
代碼結(jié)構(gòu):
<div class="main_container"><!-- 消息框 --><div id="msgList"></div><!-- 發(fā)送消息 --><div class="controls"><input type="text" class="pushMsg" /><button id="btn">發(fā)送</button></div>
</div>
3.3 代碼邏輯
-
引入之前封裝的websocket工具類;
<script src="./utils/websocket.js"></script>
-
實例化連接websocket;
const newWebSocket = new WebSocketClient('ws:localhost:8080'); newWebSocket.connect();
-
定義消息列表,監(jiān)聽返回消息信息,根據(jù)消息展示到界面中;
// 消息列表 const msgList = []; newWebSocket.addEventListener('message', handleMessage); // 處理返回數(shù)據(jù) function handleMessage(msg) {const msgData = JSON.parse(msg.data || '{}');console.log(msgData, "返回數(shù)據(jù)====");if (msgData && typeof msgData.msg === 'string' && !msgData.msg.includes('ping')) {msgList.push({name: msgData.nickname,msg: msgData.msg,});const str = msgList.reduce((cur, next) => {let curMsg = '';if (next.msg.includes('連接')) {curMsg = `<div class="center_msg">玩家:${next.name}_${next.msg}</div>`;} else {curMsg = `<div class="msg_line"><div class="avatar">${next.name}</div><div class="msg_text">${next.msg}</div></div>`;}return cur += curMsg;}, '');$('#msgList').html(str);// 獲取設(shè)置了滾動屬性的div標(biāo)簽const div = document.getElementById('msgList');// 設(shè)置滾動的頂點坐標(biāo)為滾動的總高度div.scrollTop = div.scrollHeight;} }newWebSocket.addEventListener('message', handleMessage); // 處理返回數(shù)據(jù) function handleMessage(msg) {const msgData = JSON.parse(msg.data || '{}');console.log(msgData, "返回數(shù)據(jù)====");if (msgData && typeof msgData.msg === 'string' && !msgData.msg.includes('ping')) {msgList.push({name: msgData.nickname,msg: msgData.msg,});const str = msgList.reduce((cur, next) => {let curMsg = '';if (next.msg.includes('連接')) {curMsg = `<div class="center_msg">玩家:${next.name}_${next.msg}</div>`;} else {curMsg = `<div class="msg_line"><div class="avatar">${next.name}</div><div class="msg_text">${next.msg}</div></div>`;}return cur += curMsg;}, '');$('#msgList').html(str);// 獲取設(shè)置了滾動屬性的div標(biāo)簽const div = document.getElementById('msgList');// 設(shè)置滾動的頂點坐標(biāo)為滾動的總高度div.scrollTop = div.scrollHeight;} }
-
監(jiān)聽輸入框回車事件,與發(fā)送按鈕點擊事件,發(fā)送消息;
// 監(jiān)聽發(fā)送按鈕 $('#btn').on('click', sendMessage);// 輸入框回車事件 $('.pushMsg').keydown(function(event) {if (event.key === 'Enter') {sendMessage();} }); // 發(fā)送消息 function sendMessage() {const msg = $('.pushMsg').val();if (msg) {newWebSocket.send(`${msg}`);$('.pushMsg').val('');} }
四、涉及小知識點
-
取消滾動條的展示,發(fā)送消息后默認(rèn)展示最下方數(shù)據(jù);
#msgList::-webkit-scrollbar {width: 0; }
// 獲取設(shè)置了滾動屬性的div標(biāo)簽 const div = document.getElementById('msgList'); // 設(shè)置滾動的頂點坐標(biāo)為滾動的總高度 div.scrollTop = div.scrollHeight;
-
輸入框監(jiān)聽keydown事件,當(dāng)key為
Enter
時發(fā)送消息(也可設(shè)置其他按鍵)// 輸入框回車事件 $('.pushMsg').keydown(function(event) {if (event.key === 'Enter') {sendMessage();} });
-
取消input的光標(biāo)進(jìn)入的表框效果
outline: none;
-
鼠標(biāo)小手的出現(xiàn)
cursor: pointer;
五、聊天室完整前端源碼
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>聊天通信</title><script src="./utils/jquery.min.js"></script><script src="./utils/websocket.js"></script><style>.main_container {width: 500px;margin: auto;}#msgList {width: 500px;height: 400px;overflow: auto;border: 2px solid #8491fe;border-radius: 10px;padding: 6px;background-color: #ebffff;box-sizing: border-box;}#msgList::-webkit-scrollbar {width: 0;}.msg_line {margin: 10px 0;display: flex;flex-wrap: wrap;}.avatar {width: 30px;height: 30px;border-radius: 50%;background-color: #77ffff;text-align: center;line-height: 30px;color: #333;font-size: 12px;margin-right: 6px;}.msg_text {display: inline-block;padding: 4px 12px;border-radius: 6px;background-color: #f0f1dd;font-size: 14px;}.center_msg {text-align: center;color: #f19597;}.controls {width: 100%;display: flex;justify-content: space-between;margin-top: 10px;}input {flex: 1;outline: none;height: 34px;line-height: 34px;border: 1px solid #d8d8d8;border-radius: 4px;padding: 0 4px;color: #333;margin-right: 12px;}#btn {width: 80px;height: 34px;cursor: pointer;}</style></head><body><div class="main_container"><!-- 消息框 --><div id="msgList"></div><!-- 發(fā)送消息 --><div class="controls"><input type="text" class="pushMsg" /><button id="btn">發(fā)送</button></div></div><script src="./utils/websocket.js"></script><script>// 消息列表const msgList = [];// 初始化websocketconst newWebSocket = new WebSocketClient('ws:localhost:8080');newWebSocket.connect();window.NewWebSocket = newWebSocket;newWebSocket.addEventListener('message', handleMessage);// 處理返回數(shù)據(jù)function handleMessage(msg) {const msgData = JSON.parse(msg.data || '{}');console.log(msgData, "返回數(shù)據(jù)====");if (msgData && typeof msgData.msg === 'string' && !msgData.msg.includes('ping')) {msgList.push({name: msgData.nickname,msg: msgData.msg,});const str = msgList.reduce((cur, next) => {let curMsg = '';if (next.msg.includes('連接')) {curMsg = `<div class="center_msg">玩家:${next.name}_${next.msg}</div>`;} else {curMsg = `<div class="msg_line"><div class="avatar">${next.name}</div><div class="msg_text">${next.msg}</div></div>`;}return cur += curMsg;}, '');$('#msgList').html(str);// 獲取設(shè)置了滾動屬性的div標(biāo)簽const div = document.getElementById('msgList');// 設(shè)置滾動的頂點坐標(biāo)為滾動的總高度div.scrollTop = div.scrollHeight;}}// 監(jiān)聽發(fā)送按鈕$('#btn').on('click', sendMessage);// 輸入框回車事件$('.pushMsg').keydown(function(event) {if (event.key === 'Enter') {sendMessage();}});// 發(fā)送消息function sendMessage() {const msg = $('.pushMsg').val();if (msg) {newWebSocket.send(`${msg}`);$('.pushMsg').val('');}}</script></body>
</html>