最近开发了一款实时聊天的app,主要功能包括:
1. 注册
2. 登录
3. 个人中心管理(包括密码、昵称、头像等)
4. 好友管理
5. 群聊天管理
6. 实时聊天(群、好友)
7. 消息提醒推送
前端:
- vue (前端框架)
- vuex (全局数据管理)
- muse-ui (谷歌的一款ui框架,感觉做聊天挺不错)
- axios (请求后台数据)
- websocket (实时通讯)
- better-scroll (滑动效果)
build、config…这些不用说太多,想必大家使用过vue-cli都有所了解了。主要谈谈src下的结构吧
- assets 存放一些打包后需要使用的一些静态图片
- css 这里面我只放了一个reset.css
- pages 所有的页面开发都将放在这里面
- plugins 自己写的一些插件,这个项目中仅有Loading以及Toast
- router 路由文件夹, 这里面我放了两个一个是routes.js 和index.js,routes.js 主要是管理所有的路由,对所有路由在这里进行加载export的对象用于在index.js的new Router方法所需要传入的routes参数,这里我是这样理解的,router、routes两个名字的概念是不同的,router指的是路由管理者主要对路由进行一些配置等,而routes指的是一组路由信息,当然route就是单一的一个路由信息,所以我会在index.js中写一些对Router对象的配置,比如写一些公用的方法例如goBack回退方法挂载在router.prototype上。
- server 服务请求文件夹, 其中也分为两个文件,一个是index.js 一个是commonServices.js, index.js是对aioxs的一些默认配置比如timeout、baseURL等,而commonServices.js主要是写了一些公用的处理方法,对数据的取、请求等。
- store vuex管理文件夹
- utils 公用方法文件夹 包括localStorage.js 、 Websocket.js、 dateFormat.js
好吧,我想有的童鞋可能会问干嘛建那么多文件夹,比如公用的方法写在一个utils.js文件里不就好了么,嗯其实也不是不可以,只是我个人比较喜欢每个文件的代码量都尽量精简一些,需要什么直接import就好而不是把所有的东西都放在一个文件里面,比如我把utils里的文件的方法都提取到一个文件里面,因为是一个团队开发,如果你写了某个新方法没有在文件开头写好注释别人就不一定知道你多加了一个方法,我上一家公司就是这样,当时是使用的ng1.0+,都是前年的事了,一个公用方法文件里放了n个人的公用方法,然后一个文件的代码量就有几千行。当时也是
多人共同开发一个项目,如果今天两个人都改了这个文件里的东西然后到晚上一提交代码就发生冲突,如果我们做好模块化尽量让单个方法一个文件这样既不会发生冲突,并且如果一个人新写了一个方法也不用打开文件去开就知道xx新写了一个方法,岂不是美滋滋。
当然如果你是一个开发一个项目那么你想怎么玩儿就怎么玩儿~
import store from '@/store' //vuex
if(!'WebSocket' in window){
alert("当前浏览器不支持在线聊天功能,请更换版本较新的浏览器")
}
let ws //全局websocket对象
const baseURL = '...',
bindFunc = (cntor, model) =>{
if(!ws)
return
ws.onopen = (res) =>{
console.log('链接成功')
}
ws.onmessage = (res)=>{
console.log('接收信息成功')
let result = JSON.parse(res.data)
//先判断这条信息是否是这个人发送的, 是则再将对应的消息设置发送状态为成功,不是则直接将信息push到history中,其他则为消息推送
if(result.msgFrom == cntor.username){
for(let i = model.length - 1; i > -1 ; i--){
if(model[i].message == result.msg
&& model[i].date - new Date(result.date) == 0){
//找到发送者发送的该条信息
model[i].status = 'success'
break
}
}
}else if(model){
model.push({
username: result.msgFrom,
message: result.msg,
groupId: result.groupId,
date: new Date(result.date)
})
}else{
//主要未读消息提醒
//先清空未读消息
store.commit('addUnReadCount', result.count) //添加总的未读消息数
store.commit('addSelfUnReadCount', { //设置单个聊天室的未读消息
msgFrom: result.msgFrom,
count: result.count
})
}
}
ws.onclose = (res)=> {
console.log('链接已被关闭')
}
ws.onerror = (err) =>{
console.log(err)
}
}
export default {
connect({url, params, model, connector}){
const cntor = deepClone(connector)
url? url = baseURL + '/' + url : url = baseURL
if(JSON.stringify(params) != '{}'){
url += '?'
for(let [index, elem] of Object.entries(params)){
url = url + index + '=' + elem + '&'
}
url = url.substring(0, url.length - 1)
}
if(ws){
switch(ws.readyState){
case 0 || 1://正在连接、连接成功
let timer1 = setInterval(()=>{
console.log('关闭ws请求发送ing...')
ws.close()
if(ws.readyState == 3){
clearInterval(timer1)
ws = new WebSocket(url)
store.commit('resetUnReadInfoNum')
bindFunc(cntor, model)
}
}, 500)
break
case 2://正在关闭
let timer2 = setInterval(()=>{
ws.close()
if(ws.readyState == 3){
clearInterval(timer2)
ws = new WebSocket(url)
store.commit('resetUnReadInfoNum')
bindFunc(cntor, model)
}
}, 500)
break
default:
ws = new WebSocket(url)
store.commit('resetUnReadInfoNum')
bindFunc(cntor, model)
}
}else{
store.commit('resetUnReadInfoNum')
ws = new WebSocket(url)
bindFunc(cntor, model)
}
},
send(msg) {
if(!ws || ws.readyState != 1)
return '当前不存在websocket链接信息'
ws.send(JSON.stringify(msg))
},
close() {
if(ws.readyState == 1)
ws.close()
},
}
对于多人开发还有一个想法,一般多个人开发一个项目都是分模块来开发的,一个人搭建好总的环境后,每个模块都是放在pages中,然后每个模块建一个文件夹,这个模块文件夹中分为view、controller、services,例如login:
login.vue:
...
loginController.js:
import services from './services
export default {
data: ()=>({
//...
}),
methods: {}
}
loginServices.js:
import commonServices from '@/server/commonServices'
export default {
//...
}
对于路由文件routes.js,每个人都可以建一个自己的routes.js文件,前缀加自己的名字驼峰写法就好,因为这样写每次一个人新写一个模块的时候就不需要修改routes.js文件了,修改的也只是自己的routes文件,提交的时候就不会引起冲突了。在routes.js中:
import aRoutes from './aRoutes'
import bRoutes from './bRoutes'
export default [...aRoutes, ...bRoutes]
忙里偷闲写了这篇博文,因为是写博客的新手,所以有很多不足的地方大家随便提,我有空就改~~