參考文章
💓基礎>>使用WebSocket結合node.js實作一個線上聊天室,只需要3個檔案就完成
💓進階>>使用WebSocket結合node.js實作一個線上聊天室(進階功能:即時時間動態顯示,表情符號emoji等)
💓超進階>>使用WebSocket結合vue.js實作一個程式碼簡單明瞭的線上聊天室
Root Directory
├── front.js
├── server.js
├── styles.css
└── index.html
WebSocket加上發訊息時間,即時時間動態顯示,表情符號emoji,
發文者訊息文字顏色不同等CSS相關新功能。
front.js
// 建立 WebSocket 連接
const socket = new WebSocket('ws://localhost:3000'); // 根據您的伺服器位址和埠號設定
// 連接成功時的事件處理
socket.onopen = function(event) {
console.log('已連接至 WebSocket 伺服器');
};
// 接收到訊息時的事件處理
socket.onmessage = function(event) {
// console.log('接收到伺服器訊息:', event.data);
// 解析接收到的 JSON 資料
console.log('only event接收到伺服器訊息:', event);
console.log('before JSON.parse接收到伺服器訊息:', event.data);
const data = JSON.parse(event.data);
console.log('JSON.parse接收到伺服器訊息:', data.name+": "+data.message+";時間: "+data.time);
// 將訊息顯示在畫面上
let messageBox = document.getElementById('messageBox');
let nodeDiv=document.createElement("div");
nodeDiv.style.display = "flex"; //運用Flexbox 佈局
nodeDiv.style.justifyContent = "space-between"; // 設置 flex 容器屬性,讓兩個元素(ex:span)可以分隔最開
let nodeSpan1=document.createElement("span");
let nodeSpan2=document.createElement("span");
nodeSpan2.classList.add("timestamp"); // 添加 class 到 <span> 元素
let br = document.createElement("br");
check_name(data.name, nodeSpan1); //(確認名字name是否相同) 如果發表訊息的人是自己 就將訊息的顏色進行更改
textnode=document.createTextNode(`- ${data.name} : ${data.message}`);
texttime=document.createTextNode(`- ${data.time}`);
// 將 <span> 元素和文字節點附加到訊息框中
messageBox.appendChild(nodeDiv).appendChild(nodeSpan1).appendChild(textnode);
messageBox.appendChild(nodeDiv).appendChild(nodeSpan2).appendChild(texttime);
messageBox.appendChild(br); // 在 <span> 元素後面插入 <br> 元素
};
// 關閉連接時的事件處理
socket.onclose = function(event) {
console.log('WebSocket 連接已關閉');
};
// 送出訊息函數
document.getElementById('text_btn').addEventListener('click', () =>{
const inputName = document.getElementById('inputName').value;
const inputMessage = document.getElementById('inputMessage').value;
// 獲取當前時間
formattedTime = getTime()
// 組合名稱和訊息成為一個物件,然後將其轉換成 JSON 格式的字串
const data = JSON.stringify({ name: inputName, message: inputMessage, time: formattedTime });
socket.send(data);
document.getElementById('inputMessage').value = ''; // 清空輸入框
//產生名字在頁面上
document.querySelector('.user-name').textContent = "name: "+inputName
})
function check_name(dataname, nodeSpan1){
let inputName = document.getElementById('inputName').value;
if(dataname===inputName){
nodeSpan1.style.color = 'blue'; // 如果是自己發表的文字 將它變成Blue顏色
}
}
// 獲取當前時間函式
function getTime() {
// 獲取當前時間
const currentTime = new Date();
const hours = currentTime.getHours();
const minutes = currentTime.getMinutes();
const seconds = currentTime.getSeconds();
// 將時間補零到兩位數
// 它的作用是根據條件的真假來返回不同的值。如果條件成立,則返回冒號前面的值,否則返回冒號後面的值。
const formattedHours = hours < 10 ? `0${hours}` : hours;
const formattedMinutes = minutes < 10 ? `0${minutes}` : minutes;
const formattedSeconds = seconds < 10 ? `0${seconds}` : seconds;
const formattedTime = `${formattedHours}:${formattedMinutes}:${formattedSeconds}`; // 格式化為 HH:MM 格式
// 將格式化後的時間值作為物件返回
return formattedTime;
}
// 更新時間
function updateClock() {
// 獲取當前時間
formattedTime = getTime()
document.getElementById('realTimeClock').textContent = `Current Time: ${formattedTime}`;
}
// 每秒更新時間 //它會以指定的時間間隔執行指定的函式,不會重新整理整個網頁。
setInterval(updateClock, 1000);
// 網頁載入時先執行一次更新
updateClock();
document.getElementById('smileyButton').addEventListener('click', () => {
insertEmoji('😊'); // 插入笑臉符號
});
document.getElementById('heartButton').addEventListener('click', () => {
insertEmoji('❤️'); // 插入心形符號
});
function insertEmoji(emoji) {
const inputMessage = document.getElementById('inputMessage');
inputMessage.value += emoji;
}
👄😉
如果 nodeSpan1 是使用 let 在 socket.onmessage 函式內部宣告的,它僅在該函式的範圍內有效。
換句話說,在 check_name() 函式中是無法訪問到 nodeSpan1 的。
這是 JavaScript 變數作用域的規則:
使用 let 或 const 宣告的變數只在它們所在的區塊(通常是花括號{ }內)中有效。
因此,在 check_name() 函式內部無法直接訪問 nodeSpan1,
除非您將它作為參數傳遞給 check_name() 函式或者在更廣泛的範圍內聲明 nodeSpan1。
// 接收到訊息時的事件處理
socket.onmessage = function(event) {
check_name(data.name, nodeSpan1);
//(確認名字name是否相同) 如果發表訊息的人是自己 就將訊息的顏色進行更改
下面是呼叫的函式 >>使用參數傳遞的方法
function check_name(dataname, nodeSpan1){
let inputName = document.getElementById('inputName').value;
if(dataname===inputName){
nodeSpan1.style.color = 'blue'; // 如果是自己發表的文字 將它變成Blue顏色
}
}
👄😉
Flexbox(彈性盒子布局)是 CSS3 中的一種佈局模型,用於設計彈性且高度自適應的網頁佈局。
Flexbox 提供了簡單而強大的佈局方式,適用於建立一致、靈活且可擴展的網頁佈局,
能夠有效處理多種裝置和屏幕尺寸下的佈局需求。
display: flex; 用於將一個 HTML 元素設置為 Flex 容器,
這使得其內部的子元素可以使用 Flexbox 佈局模型。
justify-content: space-between; 是 Flex 容器的屬性之一,
用於指定 Flex 子元素在主軸上的對齊方式,
space-between 會在 Flex 容器的主軸上平均分配子元素之間的空間,
使得首尾元素分別位於容器的起始和結束處,而其餘的元素則均勻分布在中間。
// 將訊息顯示在畫面上
let messageBox = document.getElementById('messageBox');
let nodeDiv=document.createElement("div");
nodeDiv.style.display = "flex"; //運用Flexbox 佈局
nodeDiv.style.justifyContent = "space-between"; // 設置 flex 容器屬性,讓兩個元素(ex:span)可以分隔最開
👄😉
可以將指定的 class 添加到新創建的 <span> 元素中。在 classList.add 方法中,
只需將您想要添加的 class 名稱傳遞給它,它就會將該 class 添加到元素中。
let nodeSpan2=document.createElement("span");
nodeSpan2.classList.add("timestamp"); // 添加 class 到 <span> 元素
👄😉
達成即時時間動態顯示
// 更新時間
function updateClock() {
// 獲取當前時間
formattedTime = getTime()
document.getElementById('realTimeClock').textContent = `Current Time: ${formattedTime}`;
}
setInterval // 每秒更新時間,它會以指定的時間間隔執行指定的函式,不會重新整理整個網頁,此例設定間隔為1秒。
// 每秒更新時間 //它會以指定的時間間隔執行指定的函式,不會重新整理整個網頁。
setInterval(updateClock, 1000);
// 網頁載入時先執行一次更新
updateClock();
server.js
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
// 提供靜態資源(HTML 檔案)
app.use(express.static('.'));
wss.on('connection', function connection(ws) {
console.log('有新的 WebSocket 連接');
ws.on('message', function incoming(message) {
const data = JSON.parse(message);
//message = message.toString('utf-8')
console.log('server接收到Name:'+data.name+" ; "+'server接收到訊息:'+data.message+" ; "+
'server接收到Time:'+data.time);
// 廣播訊息給所有客戶端
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) { //加了client !== ws && 代表訊息不傳給自己
console.log("(沒JSON.parse)-message: ", message );
console.log("(有JSON.parse)-data: ", data );
client.send(JSON.stringify(data)); //重點!! 這裡需要再把data轉成JSON檔案一次,不然front.js前端拿不到
}
});
});
});
// 啟動伺服器監聽指定的埠口
const PORT = process.env.PORT || 3000;
server.listen(PORT, function() {
console.log(`伺服器正在監聽埠口 ${PORT}`);
});
index.html
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Example</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="chat-container">
<h1>WebSocket Chat Room</h1>
<span class="user-name">name: empty</span>
<!-- Message display area -->
<div id="messageBox"></div>
<!-- Input fields and send button -->
<div>
<label for="inputName">Name:</label>
<input type="text" id="inputName" class="chat-input" placeholder="Enter your name..."><br/><br/>
</div>
<div>
<label for="inputMessage">Text:</label>
<input type="text" id="inputMessage" class="chat-input" placeholder="Enter your message...">
<button id="smileyButton" class="emoji-button">😊</button>
<button id="heartButton" class="emoji-button">❤️</button>
</div>
<button id="text_btn" class="send-button">Send</button>
<!-- Display area for showing real-time clock -->
<div id="realTimeClock"></div>
</div>
<script src="front.js"></script>
</body>
</html>
styles.css
/* Reset some default browser styles */
body, ul {
margin: 0;
padding: 0;
}
/* Chat room container */
.chat-container {
width: 80%;
margin: 20px auto;
border: 1px solid #ccc;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
/* Style for chat messages */
#messageBox {
background-color: #f4f4f4;
padding: 10px;
margin-bottom: 10px;
border-radius: 5px;
border: 1px dashed #7a0404;
justify-content: space-between;
}
/* Style for input fields */
.chat-input {
width: calc(100% - 20px);
padding: 8px;
margin-top: 10px;
border-radius: 5px;
border: 1px solid #ccc;
}
/* Style for the send button */
.send-button {
padding: 8px 20px;
margin-top: 10px;
border-radius: 5px;
background-color: #007bff;
color: #fff;
border: none;
cursor: pointer;
}
p {
color: #460606;
}
/* Style for user names */
.user-name {
font-weight: bold;
color: #333;
font-size: 18px;
}
/* Style for timestamps */
.timestamp {
color: #500a0a;
}
#realTimeClock {
font-size: 20px;
font-weight: bold;
margin-top: 20px;
padding: 10px;
background-color: #f0c6c6;
border-radius: 5px;
}
實作講解
假設有兩個人在聊天室裡,互相傳訊息,分別為lala和蓮花,藉由network的message,
可以藉由箭頭的方向,看出訊息的傳遞方向。
↑{"name":"lala","message":"我改了時間拿取方法❤️","time":"11:40:24"} 57 11:40:24.152
↓{"name":"lala","message":"我改了時間拿取方法❤️","time":"11:40:24"} 57 11:40:24.154
↓{"name":"蓮花","message":"我有看到唷~😊","time":"11:40:35"} 52 11:40:35.186
↓{"name":"蓮花","message":"好可愛歐!!!","time":"11:40:43"} 51 11:40:43.282
↑{"name":"lala","message":"我好喜歡愛心❤️符號~~ 好Q😊","time":"11:41:00"} 63 11:41:00.088
↓{"name":"lala","message":"我好喜歡愛心❤️符號~~ 好Q😊","time":"11:41:00"} 63 11:41:00.090
↓{"name":"lala","message":"我改了時間拿取方法❤️","time":"11:40:24"} 57 11:40:24.154
↑{"name":"蓮花","message":"我有看到唷~😊","time":"11:40:35"} 52 11:40:35.183
↓{"name":"蓮花","message":"我有看到唷~😊","time":"11:40:35"} 52 11:40:35.185
↑{"name":"蓮花","message":"好可愛歐!!!","time":"11:40:43"} 51 11:40:43.279
↓{"name":"蓮花","message":"好可愛歐!!!","time":"11:40:43"} 51 11:40:43.282
↓{"name":"lala","message":"我好喜歡愛心❤️符號~~ 好Q😊","time":"11:41:00"}
沒有留言:
張貼留言
喜歡我的文章嗎? 喜歡的話可以留言回應我喔! ^^