docs: simplify js_ws example

This commit is contained in:
dragon
2026-01-29 14:15:08 +08:00
parent c630b7e34f
commit 8d7c7d2110
2 changed files with 57 additions and 364 deletions

View File

@@ -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>

View File

@@ -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;
}
} }
})() })()