作者:Nicolás Parada
译者:XianLei Gao
本文是该系列的第九篇,也是最后一篇。
◈ 第一篇: 模式
◈ 第二篇: OAuth
◈ 第三篇: 对话
◈
◈
◈
◈
◈
在这篇文章中,我们将对对话
(conversation)
聊天标题
让我们从创建 static/pages/conversation-page.js 文件开始,它包含以下内容:
import http from'../http.js'
import{ navigate }from'../router.js'
import{ avatar, escapeHTML }from'../shared.js'
exportdefaultasyncfunctionconversationPage(conversationID){
let conversation
try{
conversation =awaitgetConversation(conversationID)
}catch(err){
alert(err.message)
navigate('/',true)
return
}
const template = document.createElement('template')
template.innerHTML =`
← Back
${avatar(conversation.otherParticipant)}
${conversation.otherParticipant.username}
`
const page = template.content
return page
}
functiongetConversation(id){
return http.get('/api/conversations/'+ id)
}
此页面接收路由从 URL 中提取的会话 ID。
首先,它向 /api/ conversations/{conversationID} 发起一个 GET 请求,以获取有关对话的信息。如果出现错误,我们会将其显示,并重定向回 /。然后我们呈现有关其他参与者的信息。
对话列表
我们也会获取最新的消息并显示它们。
let conversation, messages
try{
[conversation, messages]=await Promise.all([
getConversation(conversationID),
getMessages(conversationID),
])
}
更新 conversationPage() 函数以获取消息。我们使用 Promise.all() 同时执行这两个请求。
functiongetMessages(conversationID){
return http.get(`/api/conversations/${conversationID}/messages`)
}
发起对 /api/conversations/{conversationID}/messages 的 GET 请求可以获取对话中的最新消息。
ol id="messages">ol>
现在,将该列表添加到标记中。
const messagesOList = page.getElementById('messages')
for(const message of messages.reverse()){
messagesOList.appendChild(renderMessage(message))
}
这样我们就可以将消息附加到列表中了。我们以时间倒序来显示它们。
functionrenderMessage(message){
const messageContent =escapeHTML(message.content)
const messageDate =newDate(message.createdAt).toLocaleString()
const li = document.createElement('li')
if(message.mine){
li.classList.add('owned')
}
li.innerHTML =`
${messageContent}
${messageDate}
`
return li
}
每个消息条目显示消息内容本身及其时间戳。使用 .mine,我们可以将不同的 css 类附加到条目,这样您就可以将消息显示在右侧。
消息表单
form id="message-form">
input type="text"placeholder="Type something"maxlength="480"required>
button>Sendbutton>
form>
将该表单添加到当前标记中。
page.getElementById('message-form').onsubmit =messageSubmitter(conversationID)
将事件监听器附加到 “submit” 事件。
functionmessageSubmitter(conversationID){
returnasyncev=>{
ev.preventDefault()
const form = ev.currentTarget
const input = form.querySelector('input')
const submitButton = form.querySelector('button')
input.disabled =true
submitButton.disabled =true
try{
const message =awaitcreateMessage(input.value, conversationID)
input.value =''
const messagesOList = document.getElementById('messages')
if(messagesOList ===null){
return
}
messagesOList.appendChild(renderMessage(message))
}catch(err){
if(err.statusCode ===422){
input.setCustomValidity(err.body.errors.content)
}else{
alert(err.message)
}
}finally{
input.disabled =false
submitButton.disabled =false
setTimeout(()=>{
input.focus()
},)
}
}
}
functioncreateMessage(content, conversationID){
return http.post(`/api/conversations/${conversationID}/messages`,{ content })
}
我们利用 在 “submit” 事件处理程序中获取对话 ID。它 从输入中获取消息内容,并用它对 /api/conversations/{conversationID}/messages 发出 POST 请求。然后将新创建的消息添加到列表中。
消息订阅
为了实现实时,我们还将订阅此页面中的消息流。
page.addEventListener('disconnect',subscribeToMessages(messageArriver(conversationID)))
将该行添加到 conversationPage() 函数中。
functionsubscribeToMessages(cb){
return http.subscribe('/api/messages', cb)
}
functionmessageArriver(conversationID){
returnmessage=>{
if(message.conversationID !== conversationID){
return
}
const messagesOList = document.getElementById('messages')
if(messagesOList ===null){
return
}
messagesOList.appendChild(renderMessage(message))
readMessages(message.conversationID)
}
}
functionreadMessages(conversationID){
return http.post(`/api/conversations/${conversationID}/read_messages`)
}
在这里我们仍然使用这个应用的部分来获取会话 ID。当新消息到达时,我们首先检查它是否来自此对话。如果是,我们会将消息条目预先添加到列表中,并向 /api/conversations/{conversationID}/read_messages 发起 POST 一个请求,以更新参与者上次阅读消息的时间。
本系列到此结束。消息应用现在可以运行了。
◈
◈
via:
作者: 选题: 译者: 校对:
4000520066 欢迎批评指正
All Rights Reserved 新浪公司 版权所有