使用Pusher和Vue.js构建实时聊天应用
? ? ?如今,實時通信的應用程序越來越流暢,用戶體驗也變得越來越流行。
? ? ?在本教程中,我們將使用由Chater提供的服務ChatKit提供支持的Vue.js構建實時聊天應用程序。 ChatKit服務將為我們提供在任何設備上構建聊天應用程序所需的完整后端,使我們專注于構建通過ChatKit客戶端軟件包連接到ChatKit服務的前端用戶界面。?
? ? 想從頭開始學習Vue.js嗎? 借助SitePoint Premium,可以獲取有關基礎知識,項目,技巧和工具及更多內容的Vue圖書的完整集合。 立即加入,每月只需$ 9。?
先決條件 :這是中級到高級教程。 您需要先熟悉以下概念:
Vue.js基礎
Vuex基礎
采用CSS框架
? 您還需要在計算機上安裝Node。 您可以通過從官方網站下載二進制文件或使用版本管理器來執行此操作。 這可能是最簡單的方法,因為它允許您在同一臺計算機上管理多個版本的Node。
最后,您需要使用以下命令在全球范圍內安裝Vue CLI:
npm install -g @vue/cli在撰寫本文時,Node 10.14.1和Vue CLI 3.2.1是最新版本。
關于該項目
我們將構建一個類似于Slack或Discord的基本聊天應用程序。 該應用程序將執行以下操作:
有多個頻道和房間
列出會議室成員并檢測狀態
檢測其他用戶何時開始輸入
如前所述,我們只是在構建前端。 ChatKit服務具有一個后端界面,該界面使我們可以管理用戶,權限和房間。
您可以在GitHub上找到該項目的完整代碼。https://github.com/sitepoint-editors/vue-chatkit
設置一個ChatKit實例
讓我們創建一個ChatKit實例,如果您熟悉Discord,它類似于服務器實例。
前往Pusher網站上的ChatKit頁面,然后單擊“注冊”按鈕。 系統會提示您輸入電子郵件地址和密碼,并提供使用GitHub或Google登錄的選項。
選擇最適合您的選項,然后在下一個屏幕上填寫一些詳細信息,例如姓名,帳戶類型,用戶角色等。
點擊完成入門,您將進入主Pusher儀表板。 在這里,您應該單擊ChatKit產品。
單擊創建按鈕創建一個新的ChatKit實例。 我要打電話給我的VueChatTut。
?
?
本教程將使用免費計劃。 它最多支持1,000個唯一用戶,足以滿足我們的需求。 轉到控制臺選項卡。 您需要創建一個新用戶才能上手。 繼續并單擊創建用戶按鈕。?
?
我將其命名為“ john”(用戶標識符)和“ John Wick”(顯示名稱),但是您可以根據需要命名。 下一部分很簡單:創建兩個或更多用戶。 例如:
鹽伊芙琳鹽
亨特(Ethan Hunt)
創建三個或更多房間并分配用戶。 例如:
將軍(約翰,鹽,狩獵)
武器(約翰,鹽)
戰斗(約翰·亨特)
以下是控制臺界面的快照。
?
接下來,您可以轉到“房間”選項卡,并使用選定的用戶為每個房間創建一條消息。 這是出于測試目的。 然后轉到“憑據”選項卡,并記下“實例定位器”。 我們需要激活用于生成我們的HTTP端點的測試令牌提供程序,并且還要注意這一點。
?
我們的ChatKit后端現已準備就緒。 讓我們開始構建我們的Vue.js前端。
搭建Vue.js項目
打開您的終端并按照以下步驟創建項目:
選擇手動選擇功能并回答以下問題。
?
請確保您已選擇Babel,Vuex和Vue路由器作為其他功能。 接下來,如下創建以下文件夾和文件:
?
確保按照演示創建所有文件夾和文件。 刪除上圖中沒有出現的所有不必要的文件。
對于那些在家中使用控制臺的人,以下是執行所有操作的命令:
mkdir src/assets/css mkdir src/storetouch src/assets/css/{loading.css,loading-btn.css} touch src/components/{ChatNavBar.vue,LoginForm.vue,MessageForm.vue,MessageList.vue,RoomList.vue,UserList.vue} touch src/store/{actions.js,index.js,mutations.js} touch src/views/{ChatDashboard.vue,Login.vue} touch src/chatkit.jsrm src/components/HelloWorld.vue rm src/views/{About.vue,Home.vue} rm src/store.js?
完成后,src文件夾的內容應如下所示:
. ├── App.vue ├── assets │ ├── css │ │ ├── loading-btn.css │ │ └── loading.css │ └── logo.png ├── chatkit.js ├── components │ ├── ChatNavBar.vue │ ├── LoginForm.vue │ ├── MessageForm.vue │ ├── MessageList.vue │ ├── RoomList.vue │ └── UserList.vue ├── main.js ├── router.js ├── store │ ├── actions.js │ ├── index.js │ └── mutations.js └── views├── ChatDashboard.vue└── Login.vue?
對于loading-btn.css和loading.css文件,可以在loading.io網站上找到它們。 這些文件在npm存儲庫中不可用,因此您需要手動下載它們并將其放置在項目中。 確保確保閱讀文檔以了解它們是什么以及如何使用可自定義的加載程序。
接下來,我們將安裝以下依賴項:
@ pusher / chatkit-client,ChatKit服務的實時客戶端界面
bootstrap-vue,一個CSS框架
時刻,日期和時間格式化實用程序
vue-chat-scroll,添加新內容后會自動滾動到底部
vuex-persist,將Vuex狀態保存在瀏覽器的本地存儲中
?
請檢查鏈接,以了解有關每個軟件包的功能以及如何配置的更多信息。
現在,讓我們配置Vue.js項目。 打開src / main.js并更新代碼,如下所示:
import Vue from 'vue' import BootstrapVue from 'bootstrap-vue' import VueChatScroll from 'vue-chat-scroll'import App from './App.vue' import router from './router' import store from './store/index'import 'bootstrap/dist/css/bootstrap.css' import 'bootstrap-vue/dist/bootstrap-vue.css' import './assets/css/loading.css' import './assets/css/loading-btn.css'Vue.config.productionTip = false Vue.use(BootstrapVue) Vue.use(VueChatScroll)new Vue({router,store,render: h => h(App) }).$mount('#app')?如下更新src / router.js:
import Vue from 'vue' import Router from 'vue-router' import Login from './views/Login.vue' import ChatDashboard from './views/ChatDashboard.vue'Vue.use(Router)export default new Router({mode: 'history',base: process.env.BASE_URL,routes: [{path: '/',name: 'login',component: Login},{path: '/chat',name: 'chat',component: ChatDashboard,}] })?更新src / store / index.js:
import Vue from 'vue' import Vuex from 'vuex' import VuexPersistence from 'vuex-persist' import mutations from './mutations' import actions from './actions'Vue.use(Vuex)const debug = process.env.NODE_ENV !== 'production'const vuexLocal = new VuexPersistence({storage: window.localStorage })export default new Vuex.Store({state: {},mutations,actions,getters: {},plugins: [vuexLocal.plugin],strict: debug })vuex-persist軟件包可確保在頁面重新加載或刷新之間保存我們的Vuex狀態。
我們的項目現在應該能夠正確編譯。 但是,暫時不要運行它,因為我們需要構建用戶界面。
構建UI界面
首先,按照以下步驟更新src / App.vue:
?接下來,我們需要定義UI組件正常工作所需的Vuex存儲狀態。 我們將轉到src / store / index.js中的Vuex商店來完成此操作。 只需更新state和getters部分,如下所示:
state: {loading: false,sending: false,error: null,user: [],reconnect: false,activeRoom: null,rooms: [],users: [],messages: [],userTyping: null }, getters: {hasError: state => state.error ? true : false },?
這些都是聊天應用程序所需的所有狀態變量。 UI使用加載狀態來確定是否應運行CSS加載器。 錯誤狀態用于存儲剛剛發生的錯誤的信息。 當我們跨過狀態變量時,我們將討論其余的狀態變量。
接下來打開src / view / Login.vue并更新如下:
<template><div class="login"><b-jumbotron header="Vue.js Chat"lead="Powered by Chatkit SDK and Bootstrap-Vue"bg-variant="info"text-variant="white"><p>For more information visit website</p><b-btn target="_blank" href="https://pusher.com/chatkit">More Info</b-btn></b-jumbotron><b-container><b-row><b-col lg="4" md="3"></b-col><b-col lg="4" md="6"><LoginForm /></b-col><b-col lg="4" md="3"></b-col></b-row></b-container></div> </template><script> import LoginForm from '@/components/LoginForm.vue'export default {name: 'login',components: {LoginForm} } </script>接下來,為src / components / LoginForm.vue插入代碼,如下所示:
<template><div class="login-form"><h5 class="text-center">Chat Login</h5><hr><b-form @submit.prevent="onSubmit"><b-alert variant="danger" :show="hasError">{{ error }} </b-alert><b-form-group id="userInputGroup"label="User Name"label-for="userInput"><b-form-input id="userInput"type="text"placeholder="Enter user name"v-model="userId"autocomplete="off":disabled="loading"required></b-form-input></b-form-group><b-button type="submit"variant="primary"class="ld-ext-right"v-bind:class="{ running: loading }":disabled="isValid">Login <div class="ld ld-ring ld-spin"></div></b-button></b-form></div> </template><script> import { mapState, mapGetters } from 'vuex'export default {name: 'login-form',data() {return {userId: '',}},computed: {isValid: function() {const result = this.userId.length < 3;return result ? result : this.loading},...mapState(['loading','error']),...mapGetters(['hasError'])} } </script>如前所述,這是高級教程。 如果您在此處無法理解任何代碼,請轉至先決條件或項目依賴項以獲取信息。
現在,我們可以通過npm run serve啟動Vue開發服務器,以確保我們的應用程序運行時沒有任何編譯問題。
?
?
您可以通過輸入用戶名來確認驗證工作正常。 輸入三個字符后,您應該看到“登錄”按鈕被激活。 登錄按鈕暫時無法使用,因為我們尚未對該部分進行編碼。 我們待會再調查。 現在,讓我們繼續構建我們的聊天用戶界面。
轉到src / view / ChatDashboard.vue并按如下所示插入代碼:
<template><div class="chat-dashboard"><ChatNavBar /><b-container fluid class="ld-over" v-bind:class="{ running: loading }"><div class="ld ld-ring ld-spin"></div><b-row><b-col cols="2"><RoomList /></b-col><b-col cols="8"><b-row><b-col id="chat-content"><MessageList /></b-col></b-row><b-row><b-col><MessageForm /></b-col></b-row></b-col><b-col cols="2"><UserList /></b-col></b-row></b-container></div> </template><script> import ChatNavBar from '@/components/ChatNavBar.vue' import RoomList from '@/components/RoomList.vue' import MessageList from '@/components/MessageList.vue' import MessageForm from '@/components/MessageForm.vue' import UserList from '@/components/UserList.vue' import { mapState } from 'vuex';export default {name: 'Chat',components: {ChatNavBar,RoomList,UserList,MessageList,MessageForm},computed: {...mapState(['loading'])} } </script>?
ChatDashboard將充當以下子組件的布局父對象:
報表廣告
ChatNavBar,基本的導航欄
RoomList,列出已登錄用戶有權訪問的房間,它也是房間選擇器
UserList,列出選定房間的成員
MessageList,顯示在選定房間中發布的消息
MessageForm,用于將消息發送到所選房間的表單
讓我們在每個組件中添加一些樣板代碼,以確保所有內容都能顯示出來。
插入src / components / ChatNavBar.vue的樣板代碼,如下所示:
<template><b-navbar id="chat-navbar" toggleable="md" type="dark" variant="info"><b-navbar-brand href="#">Vue Chat</b-navbar-brand><b-navbar-nav class="ml-auto"><b-nav-text>{{ user.name }} | </b-nav-text><b-nav-item href="#" active>Logout</b-nav-item></b-navbar-nav></b-navbar> </template><script> import { mapState } from 'vuex'export default {name: 'ChatNavBar',computed: {...mapState(['user',])}, } </script><style>#chat-navbar {margin-bottom: 15px;} </style>插入src / components / RoomList.vue的樣板代碼,如下所示:
<template><div class="room-list"><h4>Channels</h4><hr><b-list-group v-if="activeRoom"><b-list-group-item v-for="room in rooms":key="room.name":active="activeRoom.id === room.id"href="#"@click="onChange(room)"># {{ room.name }}</b-list-group-item></b-list-group></div> </template><script> import { mapState } from 'vuex'export default {name: 'RoomList',computed: {...mapState(['rooms','activeRoom']),} } </script>插入src / components / UserList.vue的樣板代碼,如下所示:
<template><div class="user-list"><h4>Members</h4><hr><b-list-group><b-list-group-item v-for="user in users" :key="user.username">{{ user.name }}<b-badge v-if="user.presence":variant="statusColor(user.presence)"pill>{{ user.presence }}</b-badge></b-list-group-item></b-list-group></div> </template><script> import { mapState } from 'vuex'export default {name: 'user-list',computed: {...mapState(['loading','users'])},methods: {statusColor(status) {return status === 'online' ? 'success' : 'warning'}} } </script>插入src / components / MessageList.vue的樣板代碼,如下所示:
<template><div class="message-list"><h4>Messages</h4><hr><div id="chat-messages" class="message-group" v-chat-scroll="{smooth: true}"><div class="message" v-for="(message, index) in messages" :key="index"><div class="clearfix"><h4 class="message-title">{{ message.name }}</h4><small class="text-muted float-right">@{{ message.username }}</small></div><p class="message-text">{{ message.text }}</p><div class="clearfix"><small class="text-muted float-right">{{ message.date }}</small></div></div></div></div> </template><script> import { mapState } from 'vuex'export default {name: 'message-list',computed: {...mapState(['messages',])} } </script><style> .message-list {margin-bottom: 15px;padding-right: 15px; } .message-group {height: 65vh !important;overflow-y: scroll; } .message {border: 1px solid lightblue;border-radius: 4px;padding: 10px;margin-bottom: 15px; } .message-title {font-size: 1rem;display:inline; } .message-text {color: gray;margin-bottom: 0; } .user-typing {height: 1rem; } </style>插入src / components / MessageForm.vue的樣板代碼,如下所示:
<template><div class="message-form ld-over"><small class="text-muted">@{{ user.username }}</small><b-form @submit.prevent="onSubmit" class="ld-over" v-bind:class="{ running: sending }"><div class="ld ld-ring ld-spin"></div><b-alert variant="danger" :show="hasError">{{ error }} </b-alert><b-form-group><b-form-input id="message-input"type="text"v-model="message"placeholder="Enter Message"autocomplete="off"required></b-form-input></b-form-group><div class="clearfix"><b-button type="submit" variant="primary" class="float-right">Send</b-button></div></b-form></div> </template><script> import { mapState, mapGetters } from 'vuex'export default {name: 'message-form',data() {return {message: ''}},computed: {...mapState(['user','sending','error','activeRoom']),...mapGetters(['hasError'])} } </script>仔細閱讀代碼,以確保一切對您而言都是個謎。 導航到http:// localhost:8080 / chat以檢查是否一切都在運行。 檢查終端和瀏覽器控制臺,以確保此時沒有錯誤。 您現在應該具有以下視圖。
?
很空吧? 讓我們轉到src / store / index.js并在狀態中插入一些模擬數據:
state: {loading: false,sending: false,error: 'Relax! This is just a drill error message',user: {username: 'Jack',name: 'Jack Sparrow'},reconnect: false,activeRoom: {id: '124'},rooms: [{id: '123',name: 'Ships'},{id: '124',name: 'Treasure'}],users: [{username: 'Jack',name: 'Jack Sparrow',presence: 'online'},{username: 'Barbossa',name: 'Hector Barbossa',presence: 'offline'}],messages: [{username: 'Jack',date: '11/12/1644',text: 'Not all treasure is silver and gold mate'},{username: 'Jack',date: '12/12/1644',text: 'If you were waiting for the opportune moment, that was it'},{username: 'Hector',date: '12/12/1644',text: 'You know Jack, I thought I had you figured out'}],userTyping: null },保存文件后,您的視圖應與下圖匹配。
?
這個簡單的測試可確保所有組件和狀態都很好地捆綁在一起。 現在,您可以將狀態代碼恢復為原始形式:
state: {loading: false,sending: false,error: null,user: null,reconnect: false,activeRoom: null,rooms: [],users: [],messages: [],userTyping: null }讓我們從登錄表單開始實施具體功能。
無密碼認證
在本教程中,我們將采用無密碼的非安全身份驗證系統。 適當的安全身份驗證系統不在本教程的討論范圍之內。 首先,我們需要開始構建自己的界面,該界面將通過@ pusher / chatkit-client軟件包與ChatKit服務進行交互。
返回到ChatKit儀表板并復制實例和測試令牌參數。 將它們保存在項目根目錄下的.env.local文件中,如下所示:
VUE_APP_INSTANCE_LOCATOR= VUE_APP_TOKEN_URL= VUE_APP_MESSAGE_LIMIT=10?
我還添加了一個MESSAGE_LIMIT參數。 該值僅限制了我們的聊天應用程序可獲取的消息數。 確保在“憑據”選項卡中填寫其他參數。
接下來,轉到src / chatkit.js開始構建我們的聊天應用程序基礎:
import { ChatManager, TokenProvider } from '@pusher/chatkit-client'const INSTANCE_LOCATOR = process.env.VUE_APP_INSTANCE_LOCATOR; const TOKEN_URL = process.env.VUE_APP_TOKEN_URL; const MESSAGE_LIMIT = Number(process.env.VUE_APP_MESSAGE_LIMIT) || 10;let currentUser = null; let activeRoom = null;async function connectUser(userId) {const chatManager = new ChatManager({instanceLocator: INSTANCE_LOCATOR,tokenProvider: new TokenProvider({ url: TOKEN_URL }),userId});currentUser = await chatManager.connect();return currentUser; }export default {connectUser }?
請注意,我們正在將MESSAGE_LIMIT常量強制轉換為數字,因為默認情況下,process.env對象將其所有屬性強制為字符串類型。
為src / store / mutations插入以下代碼:
export default {setError(state, error) {state.error = error;},setLoading(state, loading) {state.loading = loading;},setUser(state, user) {state.user = user;},setReconnect(state, reconnect) {state.reconnect = reconnect;},setActiveRoom(state, roomId) {state.activeRoom = roomId;},setRooms(state, rooms) {state.rooms = rooms},setUsers(state, users) {state.users = users},clearChatRoom(state) {state.users = [];state.messages = [];},setMessages(state, messages) {state.messages = messages},addMessage(state, message) {state.messages.push(message)},setSending(state, status) {state.sending = status},setUserTyping(state, userId) {state.userTyping = userId},reset(state) {state.error = null;state.users = [];state.messages = [];state.rooms = [];state.user = null} }?
?突變的代碼非常簡單-只是一堆設置器。 您將很快在后面的部分中了解每個突變功能的作用。 接下來,使用以下代碼更新src / store / actions.js:
import chatkit from '../chatkit';// Helper function for displaying error messages function handleError(commit, error) {const message = error.message || error.info.error_description;commit('setError', message); }export default {async login({ commit, state }, userId) {try {commit('setError', '');commit('setLoading', true);// Connect user to ChatKit serviceconst currentUser = await chatkit.connectUser(userId);commit('setUser', {username: currentUser.id,name: currentUser.name});commit('setReconnect', false);// Test state.userconsole.log(state.user);} catch (error) {handleError(commit, error)} finally {commit('setLoading', false);}} }?
接下來,如下更新src / components / LoginForm.vue:
import { mapState, mapGetters, mapActions } from 'vuex'//... export default {//...methods: {...mapActions(['login']),async onSubmit() {const result = await this.login(this.userId);if(result) {this.$router.push('chat');}}} }您必須重新啟動Vue.js服務器才能加載env.local數據。 如果看到有關未使用變量的任何錯誤,請暫時將其忽略。 完成此操作后,導航至http:// localhost:8080 /并測試登錄功能:
?
在上面的示例中,我使用了錯誤的用戶名,只是為了確保錯誤處理功能正常運行。
?
?
?在此屏幕截圖中,我使用了正確的用戶名。 我還打開了瀏覽器控制臺標簽,以確保已填充用戶對象。 更妙的是,如果您在Chrome或Firefox中安裝了Vue.js開發工具,則應該能夠看到更多詳細信息。
?
如果目前一切正常,請繼續執行下一步。
訂閱房間
現在我們已經成功驗證了登錄功能是否正常,我們需要將用戶重定向到ChatDashboard視圖。 代碼this。$ router.push('chat'); 為我們做到這一點。 但是,我們的操作登錄名需要返回一個布爾值,以確定何時可以導航到ChatDashboard視圖。 我們還需要使用來自ChatKit服務的實際數據填充RoomList和UserList組件。
如下更新src / chatkit.js:
//... import moment from 'moment' import store from './store/index'//... function setMembers() {const members = activeRoom.users.map(user => ({username: user.id,name: user.name,presence: user.presence.state}));store.commit('setUsers', members); }async function subscribeToRoom(roomId) {store.commit('clearChatRoom');activeRoom = await currentUser.subscribeToRoom({roomId,messageLimit: MESSAGE_LIMIT,hooks: {onMessage: message => {store.commit('addMessage', {name: message.sender.name,username: message.senderId,text: message.text,date: moment(message.createdAt).format('h:mm:ss a D-MM-YYYY')});},onPresenceChanged: () => {setMembers();},onUserStartedTyping: user => {store.commit('setUserTyping', user.id)},onUserStoppedTyping: () => {store.commit('setUserTyping', null)}}});setMembers();return activeRoom; }export default {connectUser,subscribeToRoom }?
如果您查看鉤子部分,那么ChatKit服務將使用事件處理程序與客戶端應用程序進行通信。 您可以在此處找到完整的文檔。 我將快速總結每種鉤子方法的目的:
onMessage接收消息
當用戶登錄或注銷時,onPresenceChanged會收到一個事件
onUserStartedTyping接收到用戶正在鍵入的事件
onUserStoppedTyping收到用戶停止輸入的事件
為了使onUserStartedTyping正常工作,我們需要在用戶鍵入時從MessageForm發出鍵入事件。 我們將在下一部分中對此進行研究。
使用以下代碼更新src / store / actions.js中的登錄功能:
//... try {//... (place right after the `setUser` commit statement)// Save list of user's rooms in storeconst rooms = currentUser.rooms.map(room => ({id: room.id,name: room.name}))commit('setRooms', rooms);// Subscribe user to a roomconst activeRoom = state.activeRoom || rooms[0]; // pick last used room, or the first onecommit('setActiveRoom', {id: activeRoom.id,name: activeRoom.name});await chatkit.subscribeToRoom(activeRoom.id);return true; } catch (error) {//... }保存代碼后,返回登錄屏幕并輸入正確的用戶名。 您應該進入以下屏幕。
?
真好!幾乎所有組件都可以正常工作,因為我們已將它們正確連接到Vuex商店。嘗試通過ChatKit的信息中心控制臺界面發送消息。創建一條消息并將其發布到常規室。您應該看到新消息自動在MessageList組件中彈出。很快,我們將實現從Vue.js應用發送消息的邏輯。
如果您遇到問題
如果遇到問題,請嘗試以下操作:
重新啟動Vue.js服務器
清除瀏覽器緩存
進行硬重置/刷新(如果“控制臺”標簽處于打開狀態并且按住“重新加載”按鈕五秒鐘,則在Chrome中可用)
使用瀏覽器控制臺清除localStorage
如果到目前為止一切正常,請繼續執行下一部分,在該部分中實現更改房間的邏輯。
更衣室
這部分非常簡單,因為我們已經奠定了基礎。首先,我們將創建一個操作,允許用戶更改房間。轉到src / store / actions.js并在登錄操作處理程序之后添加此函數:
接下來,轉到src / components / RoomList.vue并按如下所示更新腳本部分:
import { mapState, mapActions } from 'vuex' //... export default {//...methods: {...mapActions(['changeRoom']),onChange(room) {this.changeRoom(room.id)}} }您還記得嗎,我們已經在b-list-group-item元素中定義了@ click =“ onChange(room)”。 讓我們通過單擊RoomList組件中的項目來測試這項新功能。
?
您的用戶界面應隨房間的每次點擊而更新。 MessageList和UserList組件應顯示所選房間的正確信息。在下一節中,我們將一次實現多種功能。
頁面刷新后重新連接用戶
您可能已經注意到,對store / index.js進行某些更改或刷新頁面時,會出現以下錯誤:無法讀取null的屬性'subscribeToRoom'。發生這種情況是因為您的應用程序狀態被重置。幸運的是,vuex-persist軟件包通過將頁面保存在瀏覽器的本地存儲中來維護頁面重新加載之間的Vuex狀態。
不幸的是,將我們的應用程序連接到ChatKit服務器的引用被重置為null。要解決此問題,我們需要執行重新連接操作。我們還需要一種方法來告訴我們的應用程序剛剛發生了頁面重新加載,并且我們的應用程序需要重新連接才能繼續正常運行。我們將在src / components / ChatNavbar.vue中實現此代碼。如下更新腳本部分:
<script> import { mapState, mapActions, mapMutations } from 'vuex'export default {name: 'ChatNavBar',computed: {...mapState(['user','reconnect'])},methods: {...mapActions(['logout','login']),...mapMutations(['setReconnect']),onLogout() {this.$router.push({ path: '/' });this.logout();},unload() {if(this.user.username) { // User hasn't logged outthis.setReconnect(true);}}},mounted() {window.addEventListener('beforeunload', this.unload);if(this.reconnect) {this.login(this.user.username);}} } </script>讓我分解事件的順序,以便您了解重新連接到ChatKit服務背后的邏輯:
卸下。頁面刷新發生時,將調用此方法。它首先檢查狀態user.username已設置。如果已注冊,則意味著用戶尚未注銷。狀態重新連接設置為true。
已安裝。每當ChatNavbar.vue剛完成渲染時,都會調用此方法。它首先為事件監聽器分配一個處理程序,該事件監聽器在頁面卸載之前被調用。它還會檢查state.reconnect是否已設置為true。如果是這樣,則執行登錄過程,從而將我們的聊天應用程序重新連接回我們的ChatKit服務。
我還添加了注銷功能,稍后我們將進行研究。
進行這些更改后,請嘗試刷新頁面。您會看到頁面自動更新,因為它會在后臺執行重新連接過程。當您切換房間時,它應該可以正常工作。
發送消息,檢測用戶鍵入并注銷
讓我們從添加以下代碼開始在src / chatkit.js中實現這些功能:
?
?
雖然sendMessage和斷開用戶功能將捆綁在ChatKit的模塊導出中,但isTyping函數將單獨導出。 這是為了允許MessageForm直接發送鍵入事件,而無需涉及Vuex存儲。
對于sendMessage和disconnectUser,我們需要更新商店,以處理錯誤處理和加載狀態通知之類的事情。 轉到src / store / actions.js并在changeRoom函數之后插入以下代碼:
async sendMessage({ commit }, message) {try {commit('setError', '');commit('setSending', true);const messageId = await chatkit.sendMessage(message);return messageId;} catch (error) {handleError(commit, error)} finally {commit('setSending', false);} }, async logout({ commit }) {commit('reset');chatkit.disconnectUser();window.localStorage.clear(); }對于注銷功能,我們調用commit('reset')將我們的商店重置為其原始狀態。 這是一項基本的安全功能,可以從瀏覽器緩存中刪除用戶信息和消息。
首先,通過添加@input指令來更新src / components / MessageForm.vue中的表單輸入以發出鍵入事件:
<b-form-input id="message-input"type="text"v-model="message"@input="isTyping"placeholder="Enter Message"autocomplete="off"required> </b-form-input>?
現在,讓我們更新src / components / MessageForm.vue的腳本部分,以處理消息發送和發出鍵入事件。 更新如下:
<script> import { mapActions, mapState, mapGetters } from 'vuex' import { isTyping } from '../chatkit.js'export default {name: 'message-form',data() {return {message: ''}},computed: {...mapState(['user','sending','error','activeRoom']),...mapGetters(['hasError'])},methods: {...mapActions(['sendMessage',]),async onSubmit() {const result = await this.sendMessage(this.message);if(result) {this.message = '';}},async isTyping() {await isTyping(this.activeRoom.id);}} } </script>?
?并在src / MessageList.vue中:
import { mapState } from 'vuex'export default {name: 'message-list',computed: {...mapState(['messages','userTyping'])} }現在,發送消息功能應該可以使用了。 為了顯示另一個用戶正在輸入的通知,我們需要添加一個元素來顯示此信息。 在消息組div之后的src / components / MessageList.vue的模板部分中添加以下代碼段:
<div class="user-typing"><small class="text-muted" v-if="userTyping">@{{ userTyping }} is typing....</small> </div>?要測試此功能,只需使用其他瀏覽器以其他用戶身份登錄并開始輸入即可。 您應該會在另一用戶的聊天窗口中看到一條通知。
?
讓我們通過實現最后一個功能注銷來結束本教程。 我們的Vuex商店已經具有必要的代碼來處理注銷過程。 我們只需要更新src / components / ChatNavBar.vue。 只需將注銷按鈕與我們之前指定的函數處理程序onLogout鏈接即可:
<b-nav-item href="#" @click="onLogout" active>Logout</b-nav-item>?而已。 現在,您可以注銷并以其他用戶身份再次登錄。
?
摘要
現在,我們到了教程的結尾。 ChatKit API使我們能夠在短時間內快速構建聊天應用程序。 如果我們要從頭開始構建類似的應用程序,則可能要花幾個星期,因為我們還必須充實后端。 此解決方案的優點在于,我們不必處理托管,管理數據庫和其他基礎結構問題。 我們可以簡單地將前端代碼構建和部署到Web,Android和IOS平臺上的客戶端設備。
請仔細閱讀文檔,因為本教程中沒有大量后端功能。 如果有時間,您可以輕松構建一個功能強大的聊天應用程序,該應用程序可以與Slack和Discord等流行的聊天產品匹敵。
轉自https://www.sitepoint.com/javascript-tooling-evolution-modern-developers-guide/
?
?
總結
以上是生活随笔為你收集整理的使用Pusher和Vue.js构建实时聊天应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自我总结:找工作面试时注意事项
- 下一篇: openwrt U盘安装php,db12