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, '广播请求音乐列表和身份信息')