当前位置: 首页 > 科技观察

构建一个即时通讯应用程序(八):首页

时间:2023-03-17 18:42:32 科技观察

本文是本系列的第八篇。第1部分:模式第2部分:OAuth第3部分:对话第4部分:消息传递第5部分:实时消息传递第6部分:仅开发登录第7部分:访问页面在.我们将添加一个用于开始对话的表单和一个包含最新对话的列表。对话框表单转到static/ages/home-page.js文件以在HTML视图中添加一些标记。在我们显示“授权用户”和“注销”按钮的部分下方添加此表单。page.getElementById('conversation-form').onsubmit=onConversationSubmit现在我们可以监听“提交”事件来创建对话。importhttpfrom'../http.js'import{navigate}from'../router.js'asyncfunctiononConversationSubmit(ev){ev.preventDefault()constform=ev.currentTargetconstinput=form.querySelector('input')input.disabled=truetry{constconversation=awaitcreateConversation(input.value)input.value=''navigate('/conversations/'+conversation.id)}catch(err){if(err.statusCode===422){input.setCustomValidity(err.body.errors.username)}else{alert(err.message)}setTimeout(()=>{input.focus()},0)}finally{input.disabled=false}}functioncreateConversation(username){returnhttp.post('/api/conversations',{username})}在提交时,我们使用用户名向/api/conversations发出POST请求,并重定向到对话页面(用于下一篇文章)。对话列表仍在这个文件中,我们将首先创建homePage()函数来异步加载对话。exportdefaultasyncfunctionhomePage(){constconversations=awaitgetConversations().catch(err=>{console.error(err)return[]})/*...*/}functiongetConversations(){returnhttp.get('/api/conversations')然后,在标记中添加一个列表以呈现对话框。将其添加到当前标记的正下方。constconversationsOList=page.getElementById('conversations')for(conversationofconversations){conversationsOList.appendChild(renderConversation(conversation))}所以我们可以将每个对话添加到这个列表中。import{avatar,escapeHTML}from'../shared.js'functionrenderConversation(conversation){constmessageContent=escapeHTML(conversation.lastMessage.content)constmessageDate=newDate(conversation.lastMessage.createdAt).toLocaleString()constli=document.createElement('li')li.dataset['id']=conversation.idif(conversation.hasUnreadMessages){li.classList.add('has-unread-messages')}li.innerHTML=`

${avatar(conversation.otherParticipant)}${conversation.otherParticipant.username}

${messageContent}${conversation.otherParticipant}}p>

`returnli}每个对话条目都包含一个指向对话页面的链接,并显示其他参与者信息和最后一条消息的预览。或者,您可以使用.hasUnreadMessages向条目添加一个类,并使用CSS进行一些样式设置。也许它是粗体或强调色。请注意,我们需要转义消息的内容。这个函数来自static/shared.js文件:exportfunctionescapeHTML(str){returnstr.replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"').replace(/'/g,''')}这可以防止用户编写的消息显示为HTML。如果用户碰巧编写了如下代码:这将非常烦人,因为脚本将被执行😅。所以,永远记得转义Content.MessageSubscribe最后但同样重要的是,我想订阅这里的消息流。function.functionsubscribeToMessages(cb){returnhttp.subscribe('/api/messages',cb)}函数subscribe()返回一个函数,该函数一旦被调用,就会关闭底层连接。这就是为什么我将它传递给“断开连接”断开连接事件的原因;因此,当用户离开页面时,事件流将被关闭。asyncfunctiononMessageArrive(message){constconversationLI=document.querySelector(`li[data-id="${message.conversationID}"]`)if(conversationLI!==null){conversationLI.classList.add('有未读消息')conversationLI.querySelector('a>div>p').textContent=message.contentconversationLI.querySelector('a>div>time').textContent=newDate(message.createdAt).toLocaleString()return}letconversationtry{对话=awaitgetConversation(message.conversationID)conversation.lastMessage=message}catch(err){console.error(err)return}constconversationsOList=document.getElementById('conversations')if(conversationsOList===null){返回}conversationsOList.insertAdjacentElement('afterbegin',renderConversation(conversation))}functiongetConversation(id){returnhttp.get('/api/conversations/'+id)}每次新消息到达时,我们都会在DOM中查询对话条目。如果找到,我们将has-unread-messages类添加到条目中,并更新视图。如果未找到,则表示该消息来自刚刚创建的新对话。我们向/api/conversations/{conversationID}发出GET请求以获取创建消息的对话并将其放在对话列表的前面。这些涵盖了主页的所有内容😊。在下一篇文章中,我们将对对话页面进行编码。源代码