昨天講完關於 WebSocket
的基本介紹,今天就讓我們直接利用這個協定做一個簡易聊天室吧!
本次的範例主要分成兩大塊,前端與後端
javascript
結合 html
melody
這個 package 進行實作今天先講講前端的部分
整體的檔案架構如下
/
/template
/html
- index.html
/css
- style.css
/js
- main.js
- main.go
以下分別說明各個組件需要寫些什麼
在一開始連入網頁時,會自動帶入 0 ~ 1000
間的亂數當作 Guest ID
,之後建立 ws
物件與 server 進行 WebSocket
連線,ws.onmessage
為處理 server
傳入的訊息,這邊使用 Guest ID
來判斷是否為自己發出的訊息
首先我們先定義好要用到的相關變數,以下為範例
message
other
div
class 名稱id
id
const LEFT = "left";
const RIGHT = "right";
const EVENT_MESSAGE = "message"
const EVENT_OTHER = "other"
const userPhotos = [
"https://www.flaticon.com/svg/static/icons/svg/3408/3408584.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408537.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408540.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408545.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408551.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408556.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408564.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408571.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408578.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408720.svg"
]
var PERSON_IMG = userPhotos[getRandomNum(0, userPhotos.length)];
var PERSON_NAME = "Guest" + Math.floor(Math.random() * 1000);
var url = "ws://" + window.location.host + "/ws?id=" + PERSON_NAME;
var ws = new WebSocket(url);
var chatroom = document.getElementsByClassName("msger-chat")
var text = document.getElementById("msg");
var send = document.getElementById("send")
function getRandomNum(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
當我們輸入完訊息按下 Enter
鍵或是滑鼠按下 送出訊息
按鈕會觸發的方法,觸發後透過 handleMessageEvent
傳送訊息至 WebSocket Server
,訊息格式 json
send.onclick = function (e) {
handleMessageEvent()
}
text.onkeydown = function (e) {
if (e.keyCode === 13 && text.value !== "") {
handleMessageEvent()
}
};
function handleMessageEvent() {
ws.send(JSON.stringify({
"event": "message",
"photo": PERSON_IMG,
"name": PERSON_NAME,
"content": text.value,
}));
text.value = "";
}
上面設定完傳送訊息,當然也要有接收訊息的部分,這邊透過 onmessage
接收 server
傳送的訊息
ws.onmessage = function (e) {
var m = JSON.parse(e.data)
var msg = ""
switch (m.event) {
case EVENT_MESSAGE:
if (m.name == PERSON_NAME) {
msg = getMessage(m.name, m.photo, RIGHT, m.content);
} else {
msg = getMessage(m.name, m.photo, LEFT, m.content);
}
break;
case EVENT_OTHER:
if (m.name != PERSON_NAME) {
msg = getEventMessage(m.name + " " + m.content)
} else {
msg = getEventMessage("您已" + m.content)
}
break;
}
insertMsg(msg, chatroom[0]);
};
function getEventMessage(msg) {
var msg = `<div class="msg-left">${msg}</div>`
return msg
}
function getMessage(name, img, side, text) {
const d = new Date()
// Simple solution for small apps
var msg = `
<div class="msg ${side}-msg">
<div class="msg-img" style="background-image: url(${img})"></div>
<div class="msg-bubble">
<div class="msg-info">
<div class="msg-info-name">${name}</div>
<div class="msg-info-time">${d.getFullYear()}/${d.getMonth()}/${d.getDay()} ${d.getHours()}:${d.getMinutes()}</div>
</div>
<div class="msg-text">${text}</div>
</div>
</div>
`
return msg;
}
function insertMsg(msg, domObj) {
domObj.insertAdjacentHTML("beforeend", msg);
domObj.scrollTop += 500;
}
最後整體的 javascript 就會像這樣
const LEFT = "left";
const RIGHT = "right";
const EVENT_MESSAGE = "message"
const EVENT_OTHER = "other"
const userPhotos = [
"https://www.flaticon.com/svg/static/icons/svg/3408/3408584.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408537.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408540.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408545.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408551.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408556.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408564.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408571.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408578.svg",
"https://www.flaticon.com/svg/static/icons/svg/3408/3408720.svg"
]
var PERSON_IMG = userPhotos[getRandomNum(0, userPhotos.length)];
var PERSON_NAME = "Guest" + Math.floor(Math.random() * 1000);
var url = "ws://" + window.location.host + "/ws?id=" + PERSON_NAME;
var ws = new WebSocket(url);
var chatroom = document.getElementsByClassName("msger-chat")
var text = document.getElementById("msg");
var send = document.getElementById("send")
send.onclick = function (e) {
handleMessageEvent()
}
text.onkeydown = function (e) {
if (e.keyCode === 13 && text.value !== "") {
handleMessageEvent()
}
};
ws.onmessage = function (e) {
var m = JSON.parse(e.data)
var msg = ""
switch (m.event) {
case EVENT_MESSAGE:
if (m.name == PERSON_NAME) {
msg = getMessage(m.name, m.photo, RIGHT, m.content);
} else {
msg = getMessage(m.name, m.photo, LEFT, m.content);
}
break;
case EVENT_OTHER:
if (m.name != PERSON_NAME) {
msg = getEventMessage(m.name + " " + m.content)
} else {
msg = getEventMessage("您已" + m.content)
}
break;
}
insertMsg(msg, chatroom[0]);
};
function handleMessageEvent() {
ws.send(JSON.stringify({
"event": "message",
"photo": PERSON_IMG,
"name": PERSON_NAME,
"content": text.value,
}));
text.value = "";
}
function getEventMessage(msg) {
var msg = `<div class="msg-left">${msg}</div>`
return msg
}
function getMessage(name, img, side, text) {
const d = new Date()
// Simple solution for small apps
var msg = `
<div class="msg ${side}-msg">
<div class="msg-img" style="background-image: url(${img})"></div>
<div class="msg-bubble">
<div class="msg-info">
<div class="msg-info-name">${name}</div>
<div class="msg-info-time">${d.getFullYear()}/${d.getMonth()}/${d.getDay()} ${d.getHours()}:${d.getMinutes()}</div>
</div>
<div class="msg-text">${text}</div>
</div>
</div>
`
return msg;
}
function insertMsg(msg, domObj) {
domObj.insertAdjacentHTML("beforeend", msg);
domObj.scrollTop += 500;
}
function getRandomNum(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
關於 css 與 html 可以直接使用我提供的範例
gin 的部分在 Day5 的時候有提過,這邊直接把 index.html
透過 /
存取,以下為範例
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.LoadHTMLGlob("template/html/*")
r.Static("/assets", "./template/assets")
r.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", nil)
})
r.Run(":5000")
}
設定完畢後透過 go run main.go
的方式啟動 Server,接著可以利用瀏覽器存取 http://127.0.0.1:5000
,如果看到以下畫面就代表前端網頁架設成功拉!
今天的範例主要是先將前端(client)端的部分先設定好,這樣明天我們在設定後端(Server)端的時候就可以直接看到效果拉!就讓我們明天繼續寫後端吧!
專案範例我放在這裡