webrtc/src/chat.js
2023-10-21 03:38:14 +08:00

141 lines
4.7 KiB
JavaScript

import { get, set, del, update, createStore, values } from 'idb-keyval'
import { Span, Button, List, ListItem, Input, createElement } from './weigets.js'
// 先不划分频道, 只有一个公共聊天室
export default class Chat {
constructor({ name, EventListeners = {}, onsend, onexit }) {
this.event = { onsend, onexit }
this.store = createStore(`db-chat-${name}`, `store-chat-${name}`)
this.ul = List({ classList: ['chat-list'] })
this.EventListeners = EventListeners
document.body.appendChild(createElement({
children: [
this.ul,
createElement({
type: 'text',
placeholder: '输入聊天内容',
style: {
height: '5rem',
margin: '1rem 2rem',
padding: '1rem',
boxSizing: 'border-box',
boxShadow: '0 0 1rem #eee',
},
onkeydown: event => {
const text = event.target.value.trim()
if (text && event.ctrlKey && event.key === 'Enter') {
this.发送消息(text)
event.target.value = ''
}
}
}, 'textarea'),
Button({
textContent: '发送(ctrl+Enter)',
onclick: event => {
const text = event.target.previousSibling.value.trim()
if (text) {
this.发送消息(text)
event.target.previousSibling.value = ''
}
},
style: {
margin: '1rem 2rem',
padding: '.5rem 1rem',
boxSizing: 'border-box',
boxShadow: '0 0 1rem #eee',
borderRadius: '1rem',
}
}),
]
}))
// 写入 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)
this.载入消息()
}
// 收到应答(对方确认消息已被接收)
answer(data) {
const { name, text, time, type } = data
const item = this.add({ name, text, time, type })
item.classList.add('disable')
}
// 添加一条消息
add({ name, text, time, type }) {
const item = ListItem({
classList: [type],
children: [
Span({ innerText: `${name} ${time} ${text}` })
]
})
this.ul.appendChild(item)
this.ul.scrollTop = this.ul.scrollHeight
return item
}
send(text) {
if (this.event.onsend) {
this.event.onsend(text)
}
}
添加元素(data) {
this.ul.appendChild(ListItem({
children: [
Span({ innerText: `${data.name} ${data.time} ${data.text}` })
]
}))
}
存储消息(data) {
const { name, text, time, type } = data
const id = window.crypto.randomUUID()
const item = { id, name, text, time, type }
set(id, item, this.store)
}
载入消息() {
values(this.store).then(items => {
items.map(item => {
item.timestamp = new Date(item.time).getTime()
return item
}).sort((a, b) => a.timestamp - b.timestamp).forEach(item => {
this.添加元素(item)
})
})
}
发送消息(text) {
const name = '我'
const time = new Date().toLocaleString()
console.log('发送消息', { name, text, time })
const type = 'text'
this.添加元素({ name, text, time, type })
this.存储消息({ name, text, time, type })
this.send({ name, text, time, type })
}
收到消息(data) {
const { name, text, time, type } = data
this.add({ name, text, time, type })
}
// 退出
exit() {
if (this.event.onexit) {
this.event.onexit()
}
}
}