vue + vuex + elementUi + socket.io 实现一个简易的在线聊天室, 提高自己在对 vue 系列在项目中应用的深度. 因为学会一个库或者框架容易, 但要结合项目使用一个库或框架就不是那么容易了.
可以达到的需求
能查看在线用户列表
能发送和接受消息
使用到的框架和库
socket.io 做为实时通讯基础
vuex/vue: 客户端 Ui 层使用
Element-ui: 客户端 Ui 组件
服务端实现
实现聊天服务器的相关功能, 包含通讯管道的创建, 用户加入, 消息的接受与转发等.
一, 通讯服务建立
build/server-config.JS: 聊天服务器的入口
- let socketIo = require('socket.io');
- let express = require('express');
- let cxt = require('../src/services-server');
- let httpPort = 9001;
- let channelId = 1
- let App = express();
- App.get('/',function(req,res){
- res.send('启动成功:' + httpPort);
- });
- let server = require('http').createServer(App);
- let io = socketIo(server);
- io.on('connection',function(socket){
- console.log('有客户端连接');
- cxt.createChannel(channelId++,socket)
- });
- server.listen(httpPort); // 用 server 连接
- console.log('io listen success !!' + httpPort);
通过 express 创建一个 server 对象, 然后利用 socketIo 创建 io 对象
然后通过 io 的 on 方法监听 connection 事件
当有客户端连接时, 触发 connection 事件, 县立即调用 "服务端上下文 (后面简称 cxt)" 的 createChannel 方法创建一个管道, 此时的管道上是没有用户信息的.
二, 创建上下文 (服务端上下文)
实现一个聊天室上下文, 包含: 用户, 房间, 消息, 管道等数组, 所以代码都在 service-server 目录中.
index.JS: 聊天室服务端上下文创建入口, 创建 context, 并初始化房间到上下文中.
context.JS: 聊天室服务端上下文类, 用户, 房间, 消息, 管道等类在此中做集中管理.
room 目录: 包含房间和房间集合的实现
channel: 服务端与客户端通讯的管道类
结合 "通讯服务建立" 中的 connectiong 事件的触, 其后转到 cxt.createChannel 方法
- createChannel (id, socket) {
- let channel = new Channel(id, socket, this)
- channel.init()
- channel.index = this.channels.length
- this.channels.push(channel)
- }
此时会创建一个管道实例, 然后初始化管道实例, 并将管道添加到管道数组中. 以下是初始化管道实例的代码:
- init () {
- let self = this
- let roomInfo = this.cxt.room.collections[0]
- this.roomInfo = roomInfo
- this.socket.join('roomId' + roomInfo.id)
- this.socket.emit(this.cxt.eventKeys.emit.sendRooms, roomInfo)
- /* send 出去一个默认的房间 */
- this.socket.on(this.cxt.eventKeys.client.registerUser,
- function (id, name) {
- console.log(id + '-' + name + '--' + self.id)
- self.cxt.createUserById(id, name, self.id)
- }) /** 新用户注册 */
- this.socket.on(this.cxt.eventKeys.client.newMsg, function (msg)
- { /** 发送消息 */
- self.notifyMsg(msg)
- console.log(msg)
- self.cxt.addMsg(msg)
- })
- this.socket.on(this.cxt.eventKeys.client.closeConn, function () {
- console.log(self.id + '-- 关闭连接')
- self.cxt.remove(self)
- })
- this.sendUsers()
- }
在初始化管道实例时做了如下事件:
将通讯 socket 添加一个到房间中, 方便后期好广播消息
向当前连接上来的 socket 发送房间信息, 设定为第一个房间
监听三个事件: 用户注册, 新消息, 关闭连接. 此处都要逻辑处理, 可以参考源码.
客户端实现
主要实现连接服务, 注册用户, 发送和接受消息的功能. 首先以 main.JS 为入口, 且需要先装配好 vue 相关配件, 如 vuex,ElemUi, 客户端通讯管道等, 然后创建 vue 实例和连接消息服务器, 代码如下:
- import '../node_modules/bootstrap/dist/CSS/bootstrap.css'
- import Vue from 'vue'
- import ElemUi from 'element-ui'
- import 'element-ui/lib/theme-default/index.css'
- import App from './App'
- import * as stores from './store'
- import { Keys } from './uitls'
- import { getCxt } from './services-client'
- let initRoomInfo = Keys.SETROOMINFO
- Vue.use(ElemUi)
- /* eslint-disable no-new */
- new Vue({
- store: stores.default,
- el: '#app',
- template: '<App/>',
- components: { App },
- created: function () {
- let self = this
- getCxt().createIo(this, function (roomInfo) {
- stores.busCxt.init()
- /** 初始化 view 与 service 层的交互层 (业务层) */
- self.$store.dispatch(initRoomInfo, roomInfo)
- getCxt().refUsers(function (users) {
- stores.busCxt.userCxt.refUsers(users)
- })
- })
- }
- })
一, 与服务端的通讯
service-client 目录中实例的与消息服务器通讯, 其中包含创建用户, 接受和发送消息等. 一个客户端只能拥有一个消息管道, 以下代码是消息管理的创建:
- import * as io from 'socket.io-client'
- import Context from './context'
- let eventKeys = require('../services-uitls/event.keys')
- let url = 'http://localhost:9001/'
- let cxt = null
- export function getCxt () {
- if (cxt == null) {
- cxt = new Context(url, eventKeys, io)
- }
- return cxt
- }
在 main.JS 中的 vue 实例的 created 勾子中调用了 Context 的 createIo 实例方法, 用于创建一个与消息服务器的连接, 并接受其中房间发送回来的房间信息. 然后就初始化业务层.
二, vuex 的结合
在 store 目录中实现, 包含了 vuex 类相关的实现, 还有业务层的实现. 其中业务层会引用 "客户端通讯管道", 而 vuex 实现类有可能会引用业务层相关实现类, 以此实现 ui 到 "消息服务器" 的通讯. store/index.JS 代码如下:
- import Vuex from 'vuex'
- import Vue from 'vue'
- import RoomViewCxt from './room/roomViewCxt'
- import UserViexCxt from './userViewCxt'
- import MsgViewCxt from './msg/msgViewCxt'
- import BusCxt from './indexForBus'
- let _busCxt = new BusCxt()
- let _rvCxt = new RoomViewCxt()
- let _uvCxt = new UserViexCxt(_busCxt.userCxt)
- let _mvCxt = new MsgViewCxt()
- let opt = {
- state: null,
- getters: null,
- mutations: null,
- actions: null
- }
- _rvCxt.use(opt)
- _uvCxt.use(opt)
- _mvCxt.use(opt)
- Vue.use(Vuex)
- let store = new Vuex.Store(opt)
- export default store
- export const busCxt = _busCxt /** 业务处理上下文 */
- export function getBusCxt () {
- return _busCxt
- }
三, 组件
组件只实现了 用户注册, 主界面容器, 消息发送和消息接受等. 组件只会引用 store 目录中相关类, 不会直接引用管道类.
Login.vue: 用户注册组件
HChat.vue: 主界面容器组件
Message/MsgWriter.vue: 发送消息组件
Message/MsgList.vue: 接受和显示消息列表组件
源码地址: https://github.com/cqhaibin/vue-Tags
本文转自: https://www.cnblogs.com/cqhaibin/p/6506182.html
更多 web 前端开发 https://www.html.cn/ 知识, 请查阅 HTML 中文网 !!
来源: http://www.css88.com/web/vue-js/16730.html