vue+django實(shí)現(xiàn)一對(duì)一聊天功能的實(shí)例代碼
vue+django實(shí)現(xiàn)一對(duì)一聊天和消息推送的功能。主要是通過(guò)websocket,由于Django不支持websocket,所以我使用了django-channels??紤]到存儲(chǔ)量的問(wèn)題,我并沒(méi)有把聊天信息存入數(shù)據(jù)庫(kù),服務(wù)端的作用相當(dāng)于一個(gè)中轉(zhuǎn)站。我只講述實(shí)現(xiàn)功能的結(jié)構(gòu)性代碼,具體的實(shí)現(xiàn)還請(qǐng)大家看源代碼。
效果展示
實(shí)現(xiàn)過(guò)程
后端
首先,我們需要先定義websocket的兩條連接路徑。ws/chat/xxx/(xxx指代聊天組)這條路徑是當(dāng)聊天雙方都進(jìn)入同一個(gè)聊天組以后,開(kāi)始聊天的路徑。push/xxx/(xxx指代用戶名)這條是指當(dāng)有一方不在聊天組,另一方的消息將通過(guò)這條路徑推送給對(duì)方。ws/chat/xxx/只有雙方都進(jìn)入聊天組以后才開(kāi)啟,而push/xxx/是自用戶登錄以后,直至退出都開(kāi)啟的。
websocket_urlpatterns = [ url(r'^ws/chat/(?P<group_name>[^/]+)/$', consumers.ChatConsumer), url(r'^push/(?P<username>[0-9a-z]+)/$', consumers.PushConsumer), ]
我們采用user_a的id加上下劃線_加上user_b的id的方式來(lái)命名聊天組名。其中id值從小到大放置,例如:195752_748418。當(dāng)用戶通過(guò)ws/chat/group_name/
的方式向服務(wù)端請(qǐng)求連接時(shí),后端會(huì)把這個(gè)聊天組的信息放入一個(gè)字典里。當(dāng)連接關(guān)閉時(shí),就把聊天組從字典里移除。
class ChatConsumer(AsyncJsonWebsocketConsumer): chats = dict() async def connect(self): self.group_name = self.scope['url_route']['kwargs']['group_name'] await self.channel_layer.group_add(self.group_name, self.channel_name) # 將用戶添加至聊天組信息chats中 try: ChatConsumer.chats[self.group_name].add(self) except: ChatConsumer.chats[self.group_name] = set([self]) #print(ChatConsumer.chats) # 創(chuàng)建連接時(shí)調(diào)用 await self.accept() async def disconnect(self, close_code): # 連接關(guān)閉時(shí)調(diào)用 # 將關(guān)閉的連接從群組中移除 await self.channel_layer.group_discard(self.group_name, self.channel_name) # 將該客戶端移除聊天組連接信息 ChatConsumer.chats[self.group_name].remove(self) await self.close()
接著,我們需要判斷連接這個(gè)聊天組的用戶個(gè)數(shù)。當(dāng)有兩個(gè)用戶連接這個(gè)聊天組時(shí),我們就直接向這個(gè)聊天組發(fā)送信息。當(dāng)只有一個(gè)用戶連接這個(gè)聊天組時(shí),我們就通過(guò)push/xxx/把信息發(fā)給接收方。
async def receive_json(self, message, **kwargs): # 收到信息時(shí)調(diào)用 to_user = message.get('to_user') # 信息發(fā)送 length = len(ChatConsumer.chats[self.group_name]) if length == 2: await self.channel_layer.group_send( self.group_name, { "type": "chat.message", "message": message.get('message'), }, ) else: await self.channel_layer.group_send( to_user, { "type": "push.message", "event": {'message': message.get('message'), 'group': self.group_name} }, ) async def chat_message(self, event): # Handles the "chat.message" event when it's sent to us. await self.send_json({ "message": event["message"], }) # 推送consumer class PushConsumer(AsyncWebsocketConsumer): async def connect(self): self.group_name = self.scope['url_route']['kwargs']['username'] await self.channel_layer.group_add( self.group_name, self.channel_name ) await self.accept() async def disconnect(self, close_code): await self.channel_layer.group_discard( self.group_name, self.channel_name ) # print(PushConsumer.chats) async def push_message(self, event): print(event) await self.send(text_data=json.dumps({ "event": event['event'] }))
前端
前端實(shí)現(xiàn)websocket就比較簡(jiǎn)單了。就是對(duì)websocket進(jìn)行初始化,定義當(dāng)websocket連接、關(guān)閉和接收消息時(shí)要執(zhí)行哪些動(dòng)作。
<script> export default { name : 'test', data() { return { websock: null, } }, created() { this.initWebSocket(); }, destroyed() { this.websock.close() //離開(kāi)路由之后斷開(kāi)websocket連接 }, methods: { initWebSocket(){ //初始化weosocket const wsuri = "ws://127.0.0.1:8080"; this.websock = new WebSocket(wsuri); this.websock.onmessage = this.websocketonmessage; this.websock.onopen = this.websocketonopen; this.websock.onerror = this.websocketonerror; this.websock.onclose = this.websocketclose; }, websocketonopen(){ //連接建立之后執(zhí)行send方法發(fā)送數(shù)據(jù) let actions = {"test":"12345"}; this.websocketsend(JSON.stringify(actions)); }, websocketonerror(){//連接建立失敗重連 this.initWebSocket(); }, websocketonmessage(e){ //數(shù)據(jù)接收 const redata = JSON.parse(e.data); }, websocketsend(Data){//數(shù)據(jù)發(fā)送 this.websock.send(Data); }, websocketclose(e){ //關(guān)閉 console.log('斷開(kāi)連接',e); }, }, } </script>
參考文章
Django Channels 實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)實(shí)時(shí)聊天和消息推送
總結(jié)
以上所述是小編給大家介紹的vue+django實(shí)現(xiàn)一對(duì)一聊天功能的實(shí)例代碼,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
- 基于django channel實(shí)現(xiàn)websocket的聊天室的方法示例
- Django Channel實(shí)時(shí)推送與聊天的示例代碼
- Django Channels 實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)實(shí)時(shí)聊天和消息推送功能
- Python使用django框架實(shí)現(xiàn)多人在線匿名聊天的小程序
- django使用channels實(shí)現(xiàn)通信的示例
- 淺談django channels 路由誤導(dǎo)
- 詳解Django-channels 實(shí)現(xiàn)WebSocket實(shí)例
- Django使用Channels實(shí)現(xiàn)WebSocket的方法
- django使用channels2.x實(shí)現(xiàn)實(shí)時(shí)通訊
- Django使用channels + websocket打造在線聊天室
相關(guān)文章
Vue cli構(gòu)建及項(xiàng)目打包以及出現(xiàn)的問(wèn)題解決
這篇文章主要介紹了Vue cli構(gòu)建及項(xiàng)目打包以及出現(xiàn)的問(wèn)題解決,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08vue使用html2canvas和jspdf將html轉(zhuǎn)成pdf
在前端開(kāi)發(fā)中, html轉(zhuǎn)pdf是最常見(jiàn)的需求,下面這篇文章主要給大家介紹了關(guān)于vue如何使用html2canvas和jspdf將html轉(zhuǎn)成pdf的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-03-03vue組件中iview的modal組件爬坑問(wèn)題之modal的顯示與否應(yīng)該是使用v-show
這篇文章主要介紹了vue組件中iview的modal組件爬坑問(wèn)題之modal的顯示與否應(yīng)該是使用v-show,本文通過(guò)實(shí)例圖文相結(jié)合的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04在Vue中使用deep深度選擇器修改element UI組件的樣式
這篇文章主要介紹了在Vue中使用deep深度選擇器修改element UI組件的樣式,本文分為兩種方法給大家介紹,在這小編比較推薦使用第二種使用 deep 深度選擇器,感興趣的朋友跟隨小編一起看看吧2022-12-12Vue中的echarts圖表如何實(shí)現(xiàn)loading效果
這篇文章主要介紹了Vue中的echarts圖表如何實(shí)現(xiàn)loading效果,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08vue項(xiàng)目element-ui級(jí)聯(lián)選擇器el-cascader回顯的問(wèn)題及解決
這篇文章主要介紹了vue項(xiàng)目element-ui級(jí)聯(lián)選擇器el-cascader回顯的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07