本文是系列文章的第八篇。第1部分:模式第2部分:OAuth第3部分:对话框第4部分:消息传递第5部分:实时消息传递第6部分:仅限开发的登录第7部分:访问页面第8部分:主页在这里在本文中,我们将编写对话页面。此页面是两个用户之间的聊天室。在顶部,我们将显示来自其他参与者的信息,下面是最新消息列表,底部是消息表单。ChatHeader让我们首先创建包含以下内容的static/pages/conversation-page.js文件:importhttpfrom'../http.js'import{navigate}from'../router.js'import{avatar,escapeHTML}从'../shared.js'exportdefaultasyncfunctionconversationPage(conversationID){letconversationtry{conversation=awaitgetConversation(conversationID)}catch(err){alert(err.message)navigate('/',true)return}consttemplate=document.createElement('template')template.innerHTML=`
←返回${avatar(conversation.otherParticipant)}${conversation.otherParticipant.username} `constpage=template.contentreturnpage}functiongetConversation(id){returnhttp.get('/api/conversations/'+id)}这个页面接收到路由从URL中提取的会话ID。首先,它向/api/conversations/{conversationID}发出GET请求以获取有关对话的信息。如果有错误,我们会显示它并重定向回/。然后我们提供有关其他参与者的信息。聊天列表我们还获取最新消息并显示它们。letconversation,messagestry{[conversation,messages]=awaitPromise.all([getConversation(conversationID),getMessages(conversationID),])}更新conversationPage()函数以获取消息。我们使用Promise.all()同时执行两个请求。functiongetMessages(conversationID){returnhttp.get(`/api/conversations/${conversationID}/messages`)}向/api/conversations/{conversationID}/messages发起GET请求以获取对话中的最新消息。
现在将此列表添加到标记中。constmessagesOList=page.getElementById('messages')for(constmessageofmessages.reverse()){messagesOList.appendChild(renderMessage(message))}这样我们就可以将消息附加到列表中。我们以相反的时间顺序显示它们。functionrenderMessage(消息){constmessageContent=escapeHTML(message.content)constmessageDate=newDate(message.createdAt).toLocaleString()constli=document.createElement('li')if(message.mine){li.classList.add('owned')}li.innerHTML=`${messageContent}
`returnli}每个消息条目显示消息内容本身及其时间戳。使用.mine,我们可以将不同的css类附加到条目,这样您就可以在右侧显示消息。消息表单将此表单添加到当前标记。page.getElementById('message-form').onsubmit=messageSubmitter(conversationID)将事件侦听器附加到“提交”事件。functionmessageSubmitter(conversationID){returnasyncev=>{ev.preventDefault()constform=ev.currentTargetconstinput=form.querySelector('input')constsubmitButton=form.querySelector('button')input.disabled=truesubmitButton.disabled=truetry{constmessage=awaitcreateMessage(input.value,conversationID)input.value=''constmessagesOList=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=falsesubmitButton.disabled=falsesetTimeout(()=>{input.focus()},0)}}}functioncreateMessage(content,conversationID){returnhttp.post(`/api/conversations/${conversationID}/messages`,{content})}我们在“提交”中使用部分应用”事件处理程序来获取对话ID。它从输??入中获取消息内容,并使用它向/api/conversations/{conversationID}/messages发出POST请求。然后添加新的创建消息到列表。新闻订阅对于实时,我们也会订阅本页面的新闻流。page.addEventListener('disconnect',subscribeToMessages(messageArriver(conversationID)))将此行添加到conversationPage()函数。functionssubscribeToMessages(cb){returnhttp.subscribe('/api/messages',cb)}functionmessageArriver(conversationID){returnmessage=>{if(message.conversationID!==conversationID){return}constmessagesOList=document.getElementById('消息')if(messagesOList===null){return}messagesOList.appendChild(renderMessage(message))readMessages(message.conversationID)}}functionreadMessages(conversationID){returnhttp.post(`/api/conversations/${conversationID}/read_messages`)}这里我们仍然使用这部分应用程序来获取会话id。当新消息到达时,我们首先检查它是否来自此对话。如果是这样,我们将消息条目添加到列表中,并向/api/conversations/{conversationID}/read_messages发出POST请求以更新参与者上次阅读消息的时间。本系列到此结束。消息传递应用程序现在可以运行了。源代码演示