From b14aaa6ec39a2049d650711cbbea04bba4e62ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A7=89?= Date: Wed, 18 Oct 2023 23:54:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=81=8A=E5=A4=A9=E5=AE=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat.js | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.js | 40 ++++++++++++++++++++++++++-- 2 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 src/chat.js diff --git a/src/chat.js b/src/chat.js new file mode 100644 index 0000000..af084e6 --- /dev/null +++ b/src/chat.js @@ -0,0 +1,75 @@ +import { Span, Button, List, ListItem } from './weigets.js' + +// 先不划分频道, 只有一个公共聊天室 +export default class Chat { + constructor({ EventListeners = {}, onsend, onexit }) { + this.event = { onsend, onexit } + this.ul = List({ classList: ['chat-list'] }) + this.EventListeners = EventListeners + document.body.appendChild(this.ul) // 元素加入页面 + + // 添加输入框 + const input = document.createElement('input') + input.type = 'text' + input.placeholder = '输入聊天内容' + input.style.width = '100%' + input.style.height = '5rem' + input.style.margin = '1rem 2rem' + input.addEventListener('keydown', event => { + if (event.key === 'Enter') { + const text = input.value.trim() + if (text) { + this.send(text) + input.value = '' + } + } + }) + document.body.appendChild(input) + + // 写入 css 样式到 head + const style = document.createElement('style') + style.innerText = ` + ul.chat-list { + max-height: 70vh; + overflow-y: auto; + } + ul.chat-list > li > span { + cursor: pointer; + } + ul.chat-list > li.play > span { + color: #02be08; + } + ul.chat-list > li.cache::marker { + color: #02be08; + font-size: 1em; + contentx: '⚡'; + } + ul.chat-list > li.disable { + color: #888; + } + ` + document.head.appendChild(style) + } + // 添加一条消息 + add({ name, text, time, type }) { + this.ul.appendChild(ListItem({ + classList: [type], + children: [ + Span({ innerText: `${name} ${time} ${text}` }) + ] + })) + this.ul.scrollTop = this.ul.scrollHeight + } + // 发送消息 + send(text) { + if (this.event.onsend) { + this.event.onsend(text) + } + } + // 退出 + exit() { + if (this.event.onexit) { + this.event.onexit() + } + } +} \ No newline at end of file diff --git a/src/main.js b/src/main.js index a1dbf7d..62edb78 100644 --- a/src/main.js +++ b/src/main.js @@ -4,6 +4,7 @@ import 'virtual:windi-devtools' import IndexedDB from './database.js' import MusicList from './music.js' import ClientList from './client.js' +import Chat from './chat.js' // 缓冲分片发送 const CHUNK_SIZE = 1024 * 64 // 默认每个块的大小为128KB @@ -140,9 +141,44 @@ const musicList = new MusicList({ } }) -const ImageList = [] +const chat = new Chat({ + onsend: async (text, list) => { + console.log('发送消息', text) + clientList.send('chat', JSON.stringify({ type: 'message', text })) + console.log('发送结束') + }, + onexit: async () => { + console.log('退出聊天室') + } +}) -// 只有一个基本信道, 用于交换和调度信息 +// 与每个客户端都建立聊天信道 +clientList.setChannel('chat', { + onopen: async event => { + console.debug('打开信道', event.target.label) + }, + onmessage: async (event, client) => { + const data = JSON.parse(event.data) + if (data.type === 'message') { + console.log(client.name, '发来消息:', data) + chat.add({ name: client.name, text: data.text, time: new Date().toLocaleTimeString() }) + return + } + if (data.type === 'image') { + console.log(client.name, '发来图片:', data) + return + } + console.log('未知类型:', data.type) + }, + onclose: event => { + console.log('关闭信道', event.target.label) + }, + onerror: event => { + console.error('信道错误', event.target.label, event.error) + } +}) + +// 与每个客户端都建立基本信道, 用于交换和调度信息 clientList.setChannel('base', { onopen: async event => { console.debug('打开信道', event.target.label, '广播请求音乐列表和身份信息')