docs: simplify js_ws example
This commit is contained in:
@@ -3,376 +3,80 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>WebSocket聊天客户端</title>
|
<title>Simple WebSocket Example</title>
|
||||||
<style>
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-container {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 900px;
|
|
||||||
height: 85vh;
|
|
||||||
background-color: white;
|
|
||||||
border-radius: 15px;
|
|
||||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
background: linear-gradient(to right, #4a00e0, #8e2de2);
|
|
||||||
color: white;
|
|
||||||
padding: 20px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-content {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-indicator {
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-connecting {
|
|
||||||
background-color: #ffc107;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-connected {
|
|
||||||
background-color: #28a745;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-disconnected {
|
|
||||||
background-color: #dc3545;
|
|
||||||
}
|
|
||||||
|
|
||||||
.connection-btn {
|
|
||||||
padding: 8px 16px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 600;
|
|
||||||
background: rgba(255, 255, 255, 0.2);
|
|
||||||
color: white;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.connection-btn:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.3);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-area {
|
|
||||||
flex: 1;
|
|
||||||
padding: 20px;
|
|
||||||
overflow-y: auto;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message {
|
|
||||||
max-width: 70%;
|
|
||||||
padding: 12px 18px;
|
|
||||||
border-radius: 18px;
|
|
||||||
position: relative;
|
|
||||||
line-height: 1.4;
|
|
||||||
word-wrap: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-message {
|
|
||||||
align-self: flex-end;
|
|
||||||
background: linear-gradient(to right, #4a00e0, #8e2de2);
|
|
||||||
color: white;
|
|
||||||
border-bottom-right-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.server-message {
|
|
||||||
align-self: flex-start;
|
|
||||||
background-color: white;
|
|
||||||
color: #333;
|
|
||||||
border: 1px solid #e0e0e0;
|
|
||||||
border-bottom-left-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-time {
|
|
||||||
font-size: 11px;
|
|
||||||
margin-top: 5px;
|
|
||||||
opacity: 0.7;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-area {
|
|
||||||
padding: 20px;
|
|
||||||
background-color: white;
|
|
||||||
border-top: 1px solid #e0e0e0;
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-area input {
|
|
||||||
flex: 1;
|
|
||||||
padding: 12px 15px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 25px;
|
|
||||||
outline: none;
|
|
||||||
font-size: 16px;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-area input:focus {
|
|
||||||
border-color: #8e2de2;
|
|
||||||
box-shadow: 0 0 0 2px rgba(142, 45, 226, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-btn {
|
|
||||||
padding: 12px 25px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 25px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 600;
|
|
||||||
background: linear-gradient(to right, #4a00e0, #8e2de2);
|
|
||||||
color: white;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-btn:hover {
|
|
||||||
background: linear-gradient(to right, #3a00b0, #7a1dc2);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-btn:disabled {
|
|
||||||
background: #cccccc;
|
|
||||||
cursor: not-allowed;
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-state {
|
|
||||||
text-align: center;
|
|
||||||
color: #6c757d;
|
|
||||||
margin-top: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-state i {
|
|
||||||
font-size: 48px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.chat-container {
|
|
||||||
height: 95vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message {
|
|
||||||
max-width: 85%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="chat-container">
|
<h1>Simple WebSocket Echo</h1>
|
||||||
<div class="header">
|
<div id="status">Disconnected</div>
|
||||||
<div class="header-content">
|
<div id="messages" style="border: 1px solid #ccc; height: 300px; overflow-y: scroll; padding: 10px; margin-bottom: 10px;"></div>
|
||||||
<h1>WebSocket聊天客户端</h1>
|
<input type="text" id="input" placeholder="Type a message...">
|
||||||
<div class="status">
|
<button onclick="send()">Send</button>
|
||||||
<div class="status-indicator status-disconnected"></div>
|
<button onclick="connect()">Connect</button>
|
||||||
<span id="status-text">未连接</span>
|
<button onclick="disconnect()">Disconnect</button>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button class="connection-btn" id="connectionButton" onclick="toggleConnection()">连接</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="chat-area" id="chatArea">
|
<script>
|
||||||
<div class="empty-state">
|
let ws;
|
||||||
<i>💬</i>
|
const statusDiv = document.getElementById('status');
|
||||||
<p>连接服务器开始聊天</p>
|
const messagesDiv = document.getElementById('messages');
|
||||||
</div>
|
const input = document.getElementById('input');
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="input-area">
|
function connect() {
|
||||||
<input type="text" id="messageInput" placeholder="输入消息..." disabled>
|
if (ws) return;
|
||||||
<button class="send-btn" id="sendButton" onclick="sendMessage()" disabled>发送</button>
|
// Get the current host (including port)
|
||||||
</div>
|
const host = window.location.host;
|
||||||
</div>
|
// Determine the protocol (ws or wss) based on the current page protocol
|
||||||
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||||
|
// Construct the WebSocket URL. Note the leading slash for absolute path.
|
||||||
|
// Since .pages.yaml maps "ws" to the JS handler, we connect to /ws
|
||||||
|
const wsUrl = `${protocol}//${host}/ws`;
|
||||||
|
|
||||||
<script>
|
console.log('Connecting to:', wsUrl); // Debug log
|
||||||
let ws = null;
|
ws = new WebSocket(wsUrl);
|
||||||
let isConnected = false;
|
|
||||||
const statusText = document.getElementById('status-text');
|
|
||||||
const statusIndicator = document.querySelector('.status-indicator');
|
|
||||||
const chatArea = document.getElementById('chatArea');
|
|
||||||
const messageInput = document.getElementById('messageInput');
|
|
||||||
const sendButton = document.getElementById('sendButton');
|
|
||||||
const connectionButton = document.getElementById('connectionButton');
|
|
||||||
|
|
||||||
function toggleConnection() {
|
|
||||||
if (isConnected) {
|
|
||||||
disconnect();
|
|
||||||
} else {
|
|
||||||
connect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function connect() {
|
|
||||||
updateStatus('正在连接...', 'status-connecting');
|
|
||||||
connectionButton.textContent = '连接中...';
|
|
||||||
|
|
||||||
try {
|
|
||||||
ws = new WebSocket('/ws');
|
|
||||||
|
|
||||||
ws.onopen = () => {
|
ws.onopen = () => {
|
||||||
isConnected = true;
|
statusDiv.innerText = 'Connected';
|
||||||
updateStatus('已连接', 'status-connected');
|
log('Connected to ' + wsUrl);
|
||||||
connectionButton.textContent = '断开连接';
|
|
||||||
enableControls(true);
|
|
||||||
addSystemMessage('连接成功,可以开始聊天了');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onmessage = event => {
|
ws.onmessage = (event) => {
|
||||||
addServerMessage(event.data);
|
log('Received: ' + event.data);
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onclose = () => {
|
ws.onclose = () => {
|
||||||
isConnected = false;
|
statusDiv.innerText = 'Disconnected';
|
||||||
updateStatus('未连接', 'status-disconnected');
|
log('Disconnected');
|
||||||
connectionButton.textContent = '连接';
|
ws = null;
|
||||||
enableControls(false);
|
|
||||||
addSystemMessage('连接已断开');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onerror = error => {
|
ws.onerror = (error) => {
|
||||||
isConnected = false;
|
statusDiv.innerText = 'Error';
|
||||||
updateStatus('连接错误', 'status-disconnected');
|
log('Error: ' + error);
|
||||||
connectionButton.textContent = '连接';
|
|
||||||
enableControls(false);
|
|
||||||
addSystemMessage('连接错误,请检查服务器');
|
|
||||||
};
|
};
|
||||||
} catch (error) {
|
|
||||||
isConnected = false;
|
|
||||||
updateStatus('连接失败', 'status-disconnected');
|
|
||||||
connectionButton.textContent = '连接';
|
|
||||||
enableControls(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function disconnect() {
|
|
||||||
if (ws) {
|
|
||||||
ws.close();
|
|
||||||
ws = null;
|
|
||||||
}
|
|
||||||
isConnected = false;
|
|
||||||
connectionButton.textContent = '连接';
|
|
||||||
enableControls(false);
|
|
||||||
addSystemMessage('已断开连接');
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendMessage() {
|
|
||||||
const message = messageInput.value.trim();
|
|
||||||
if (message) {
|
|
||||||
ws.send(message);
|
|
||||||
addUserMessage(message);
|
|
||||||
messageInput.value = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addUserMessage(message) {
|
|
||||||
addMessage(message, 'user');
|
|
||||||
}
|
|
||||||
|
|
||||||
function addServerMessage(message) {
|
|
||||||
addMessage(message, 'server');
|
|
||||||
}
|
|
||||||
|
|
||||||
function addSystemMessage(message) {
|
|
||||||
addMessage(message, 'system');
|
|
||||||
}
|
|
||||||
|
|
||||||
function addMessage(message, type) {
|
|
||||||
const emptyState = document.querySelector('.empty-state');
|
|
||||||
if (emptyState) {
|
|
||||||
emptyState.remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageElement = document.createElement('div');
|
function disconnect() {
|
||||||
const time = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
|
if (ws) {
|
||||||
|
ws.close();
|
||||||
if (type === 'user') {
|
}
|
||||||
messageElement.className = 'message user-message';
|
|
||||||
messageElement.innerHTML = `
|
|
||||||
${message}
|
|
||||||
<div class="message-time">${time}</div>
|
|
||||||
`;
|
|
||||||
} else if (type === 'server') {
|
|
||||||
messageElement.className = 'message server-message';
|
|
||||||
messageElement.innerHTML = `
|
|
||||||
${message}
|
|
||||||
<div class="message-time">${time}</div>
|
|
||||||
`;
|
|
||||||
} else {
|
|
||||||
messageElement.className = 'message system-message';
|
|
||||||
messageElement.style.alignSelf = 'center';
|
|
||||||
messageElement.style.maxWidth = '100%';
|
|
||||||
messageElement.style.backgroundColor = 'rgba(0,0,0,0.05)';
|
|
||||||
messageElement.style.color = '#6c757d';
|
|
||||||
messageElement.style.fontSize = '14px';
|
|
||||||
messageElement.style.textAlign = 'center';
|
|
||||||
messageElement.style.borderRadius = '10px';
|
|
||||||
messageElement.textContent = message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chatArea.appendChild(messageElement);
|
function send() {
|
||||||
chatArea.scrollTop = chatArea.scrollHeight;
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||||
}
|
const msg = input.value;
|
||||||
|
ws.send(msg);
|
||||||
function updateStatus(message, statusClass) {
|
log('Sent: ' + msg);
|
||||||
statusText.textContent = message;
|
input.value = '';
|
||||||
statusIndicator.className = 'status-indicator ' + statusClass;
|
} else {
|
||||||
}
|
alert('Not connected');
|
||||||
|
}
|
||||||
function enableControls(connected) {
|
|
||||||
messageInput.disabled = !connected;
|
|
||||||
sendButton.disabled = !connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
messageInput.addEventListener('keypress', function(event) {
|
|
||||||
if (event.key === 'Enter') {
|
|
||||||
sendMessage();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
</script>
|
function log(msg) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.innerText = msg;
|
||||||
|
messagesDiv.appendChild(div);
|
||||||
|
messagesDiv.scrollTop = messagesDiv.scrollHeight;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -2,17 +2,6 @@
|
|||||||
let ws = websocket();
|
let ws = websocket();
|
||||||
while (true) {
|
while (true) {
|
||||||
let data = await ws.readText();
|
let data = await ws.readText();
|
||||||
switch (data) {
|
await ws.writeText("ECHO: " + data)
|
||||||
case "exit":
|
|
||||||
return
|
|
||||||
case "panic":
|
|
||||||
throw Error("错误");
|
|
||||||
case "date":
|
|
||||||
await ws.writeText(new Date().toJSON())
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
await ws.writeText("收到信息:" + data)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
Reference in New Issue
Block a user