{{ info.nickname }}
├── build 项目构建配置
│ ├── updateAdapter.js 更改adapter的配置
│ ├── webpack.base.conf.js webpack公共配置
│ ├── webpack.dev.conf.js webpack测试打包配置
│ ├── webpack.local.conf.js webpack本地打包配置
│ └── webpack.prod.conf.js webpack生产打包配置
├── cache-loader 项目构建缓存
├── config 项目构建配置内容
├── dist 项目构建生成的包
├── node_modules 安装依赖包存储的地方
├── src
│ ├── api 接口定义的地方
│ ├── assets 静态资源以及样式文件存放点
│ ├── components 公共组件
│ ├── router 路由配置
│ ├── store vuex(状态管理)
│ ├── types ts类型定义存放点
│ ├── utils 公共能力
│ ├── view 视图
│ ├── App.vue 根组件
│ └── main.ts 应用配置
├── static 静态资源存储目录,该目录中的资源不做构建处理
├── .babelrc babel配置文件
├── .editorconfig 编码风格配置文件
├── .eslintignore eslint忽略文件
├── .eslintrc.js eslint配置文件
├── .gitignore git忽略文件
├── .postcssrc.js Vue移动端rem适配 —— Postcss的配置文件
├── .prettierrc.js 代码风格格式化配置文件
├── index.html html模板文件
├── package.json
├── README.md
└── yarn.lock
这里小编使用自己开发的一款脚手架@varied/cli,不硬性要求,可使用其他脚手架
npm install @varied/cli -g
varied init webpack socket-chat
这里我们安装 vant 组件库和 socket 客户端
yarn add vant@2.12.50 socket.io-client@4.5.2
这里为了图省事,小编使用全局引入,可自选选择引入方案
import Vant from 'vant';
import 'vant/lib/index.css';
Vue.use(Vant);
jsconfig.json
@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"components/*": ["src/components/*"]
}
}
}
yarn start
# 或者
npm run start
如图所示,即运行成功
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require('socket.io');
const io = new Server(server);
let rooms = {};
// 监听连接
io.on('connection', (socket) => {
console.log('a user connected');
// 监听创建聊天室
socket.on('createRoom', (data) => {
// 将聊天室id存放到rooms对象中
Object.assign(rooms, data);
console.log(data);
});
// 监听发送
socket.on('send', (data) => {
const { to, from, message } = data;
// 将取到的数据,通过receive发送到对应的聊天室
socket.to(rooms[to]).emit('receive', { from, message });
});
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
├── assets
│ └── avatar.png # 自行下载头像并存储到该位置
├── store
│ └── modules
│ │ └── user.js
│ └── index.js
├── utils
│ └── socket.js
├── view
│ ├── chat
│ │ ├── components
│ │ │ ├── receive
│ │ │ ├── └── index.vue
│ │ │ ├── send
│ │ │ └── └── index.vue
│ │ └── index.vue
│ ├── message
│ │ ├── components
│ │ │ ├── cell
│ │ │ └── └── index.vue
│ │ └── index.vue
│ ├── friends
│ │ └── index.vue
│ ├── mine
│ │ └── index.vue
store/modules/user.js
/**
* @author Wuner
* @date 2020/12/9 18:00
* @description 用户模块
*/
import Session from '@/utils/session';
import { login } from '@/api/user';
const storeState = Session.get('storeState');
const state = (storeState && storeState.user) || {
// 用户信息
userinfo: {
username: '',
nickname: '',
},
};
const getters = {};
const mutations = {
/**
* 设置用户信息
* @param state
* @param data
*/
setUserinfo(state, data) {
state.userinfo = data;
},
};
const actions = {};
export default { namespaced: true, state, getters, mutations, actions };
store/index.js
/**
* @author Wuner
* @date 2020/12/9 17:58
* @description store 配置文件
*/
import Vuex from 'vuex';
import Vue from 'vue';
import Session from '@/utils/session';
import user from './modules/user';
Vue.use(Vuex);
const myPlugin = (store) => {
store.subscribe((mutation, state) => {
// 缓存状态
Session.set('storeState', state);
});
};
const storeState = Session.get('storeState');
const state = {
data: (storeState && storeState.data) || {},
};
const getters = {
/**
* data数据
* @param state
* @returns {*}
*/
data(state) {
return state.data;
},
};
const mutations = {
/**
* 设置data数据
* @param state
* @param data
*/
setData(state, data) {
state.data = data;
},
};
const actions = {};
const store = new Vuex.Store({
// 非生产环境添加严格模式
strict: process.env.NODE_ENV !== 'production',
state,
getters,
mutations,
actions,
// 模块
modules: {
user,
},
// 插件
plugins: [myPlugin],
});
export default store;
utils/socket.js
/**
* @returns {String}
*/
import io from 'socket.io-client';
function socketUrl() {
if (process.env.NODE_ENV === 'local') {
// 测试
return `http://localhost:3000/`;
} else {
// 生产
return 'http://localhost:3000/';
}
}
export const createSocket = (username) => {
// console.log("建立websocket连接")
// 建立websocket连接,
const url = socketUrl();
const socket = (window.socket = io(url, {
transports: ['websocket'],
}));
console.log(window.socket);
// 监听客户端连接,回调函数会传递本次连接的socket
socket.on('connect', () => {
console.log('#connect,', socket.id);
const id = socket.id.replace(url, '');
console.log('#connect,', id);
let obj = {};
obj[username] = id;
// 创建聊天室
socket.emit('createRoom', obj);
});
};
main.js
router.beforeEach((to, from, next) => {
if (to.name === 'index') {
const { username } = to.query;
store.commit('user/setUserinfo', { username, nickname: username });
}
if (store.state.user.userinfo.username && !window.socket) {
createSocket(store.state.user.userinfo.username);
next();
} else {
next();
}
});
view/index.vue
消息
联系人
我的
view/chat/components/receive/index.vue
{{ info.from }}
view/chat/components/send/index.vue
{{ info.from }}
view/chat/index.vue
view/message/components/cell/index.vue
{{ info.nickname }}
view/message/index.vue
view/friends/index.vue
联系人
view/mine/index.vue
我的
router/index.js
import Vue from 'vue';
import Router from 'vue-router';
Vue.use(Router); // 启用router插件
// 以下是路由配置
let router = new Router({
mode: 'hash',
routes: [
{
path: '/',
name: 'index',
component: () => import(/*webpackChunkName: "index"*/ '@/view/index.vue'),
redirect: '/message',
children: [
{
path: '/message',
name: 'message',
component: () =>
import(/*webpackChunkName: "index"*/ '@/view/message/index.vue'),
meta: {
title: '消息',
},
},
{
path: '/friends',
name: 'friends',
component: () =>
import(/*webpackChunkName: "index"*/ '@/view/friends/index.vue'),
meta: {
title: '联系人',
},
},
{
path: '/mine',
name: 'mine',
component: () =>
import(/*webpackChunkName: "index"*/ '@/view/mine/index.vue'),
meta: {
title: '我的',
},
},
],
},
{
path: '/chat/:username',
name: 'chat',
component: () =>
import(/*webpackChunkName: "index"*/ '@/view/chat/index.vue'),
meta: {
title: '聊天',
},
},
],
});
export default router;
yarn start
# 或者
npm run start
这时浏览器会自带打开页面,在浏览器连接中,添加?username=wuner,并复制浏览器连接,将 wuner 改为 wuner1,并使用新建标签打开