效果图
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css'
import vuescroll from "vuescroll"
import "vuescroll/dist/vuescroll.css"
Vue. config. productionTip = false
Vue. use ( Antd)
Vue. use ( vuescroll)
new Vue ( {
router,
store,
render : h => h ( App)
} ) . $mount ( '#app' )
package.json
{
"name" : "cms-pc" ,
"version" : "0.1.0" ,
"private" : true ,
"scripts" : {
"serve" : "vue-cli-service serve" ,
"build" : "vue-cli-service build" ,
"electron:serve" : "vue-cli-service electron:serve" ,
"postinstall" : "electron-builder install-app-deps" ,
"postuninstall" : "electron-builder install-app-deps"
} ,
"main" : "background.js" ,
"dependencies" : {
"ant-design-vue" : "^1.7.8" ,
"axios" : "^0.24.0" ,
"core-js" : "^3.8.3" ,
"vue" : "^2.6.14" ,
"vue-router" : "^3.5.1" ,
"vuex" : "^3.6.2" ,
"electron" : "^17.1.2" ,
"vuescroll" : "^4.17.3"
} ,
"devDependencies" : {
"@vue/cli-plugin-babel" : "~5.0.0" ,
"@vue/cli-plugin-router" : "~5.0.0" ,
"@vue/cli-plugin-vuex" : "~5.0.0" ,
"@vue/cli-service" : "~5.0.0" ,
"vue-template-compiler" : "^2.6.14" ,
"less" : "^3.0.4" ,
"less-loader" : "^5.0.0" ,
"vue-cli-plugin-electron-builder" : "^1.3.5"
}
}
vue组件
< template>
< div class = " index" >
< a-row :gutter = " [10,10]" >
< a-col :span = " 24" >
< h2 v-text = " ' You are talking to: ' +message2UserId" />
< div class = " messagesWrapper" >
< vue-scroll ref = " chatMessagesScroller" :ops = " ops" style = " width : 100%; " >
< div class = " chatMessages" >
< a-row :gutter = " [10,10]" >
< a-col v-for = " (message,index) in chatMessages" :key = " index" :span = " 24" >
< div :class = " [' chatMessageItem' ,message.fromId === loginUserId ? ' send' : ' receive' ]" >
< div class = " messageAuthor" >
< a-avatar :size = " 45" icon = " user" />
</ div>
< div class = " messageInfo" >
< div class = " messageTime" > 2022-03-28</ div>
< div :class = " [' chat-bubble' ,message.fromId === loginUserId ?
' chat-bubble-right chat-bubble-success' :' chat-bubble-left chat-bubble-primary' ]"
:id = " ' chatMessage_' +index" >
< span v-text = " message.messageInfo" />
</ div>
</ div>
</ div>
</ a-col>
</ a-row>
</ div>
</ vue-scroll>
</ div>
< a-textarea v-model = " messageInfo" placeholder = " input message" rows = " 4" />
< a-button type = " primary" v-on: click= " sendMessage" icon = " enter" style = " float : right; margin-top : 10px" > send</ a-button>
</ a-col>
< a-col :xl = " 12" :lg = " 12" :md = " 12" :sm = " 24" :xs = " 24" >
< span>
当前状态:< span :style = " isLogined ? ' color:green;' :' color: red;' " v-text = " isLogined ? ' 已登录' : ' 未登录' " />
</ span>
< a-input-search v-model = " loginUserId" placeholder = " your id" @search = " imLogin" >
< a-button type = " primary" slot = " enterButton" >
login
</ a-button>
</ a-input-search>
</ a-col>
< a-col :xl = " 12" :lg = " 12" :md = " 12" :sm = " 24" :xs = " 24" >
< label> chat to user:</ label>
< a-input v-model = " message2UserId" placeholder = " chat target user id" style = " width : 100%" />
</ a-col>
</ a-row>
</ div>
</ template>
< script>
export default {
name: "index" ,
data ( ) {
return {
loginUserId: '' ,
socket: undefined ,
message2UserId: '' ,
messageInfo: '' ,
chatMessages: [ ] ,
isLogined: false ,
ops: {
vuescroll: { } ,
scrollPanel: {
scrollingX: false
} ,
rail: {
keepShow: true
} ,
bar: {
hoverStyle: true ,
onlyShowBarOnScroll: false ,
background: "#929292" ,
opacity: 0.5 ,
'overflow-x' : "hidden"
}
} ,
isSending: false ,
}
} ,
methods: {
initSocketConnect ( ) {
let that = this ;
if ( window. WebSocket || window. MozWebSocket) {
that. socket = new WebSocket ( "ws://localhost:7777/ws" ) ;
that. socket. onmessage = function ( event ) {
let messagePacket = JSON . parse ( event. data) ;
let msgCommand = messagePacket. command;
if ( msgCommand !== 'HEARTBEAT_RESPONSE' ) {
that. processMessage ( messagePacket) ;
}
} ;
that. socket. onopen = function ( event ) {
console. log ( "websocket connected" ) ;
that. startHeartBeat ( ) ;
} ;
that. socket. onclose = function ( event ) {
console. log ( "websocket disConnected" ) ;
} ;
} else {
console. log ( "your browser does not support websocket" ) ;
}
} ,
startHeartBeat ( ) {
let that = this ;
setInterval ( function ( ) {
let packet = { } ;
packet. command = "3" ;
that. socket. send ( JSON . stringify ( packet) ) ;
} , 5000 ) ;
} ,
imLogin ( ) {
let that = this ;
if ( that. loginUserId) {
let loginPacket = { } ;
loginPacket. dataInfo = {
userId: that. loginUserId,
password: "123456" ,
clientType: "web" ,
clientVersion: "1" ,
} ;
loginPacket. command = "1" ;
that. socket. send ( JSON . stringify ( loginPacket) ) ;
that. isLogined = true ;
} else {
that. $notification[ 'info' ] ( {
message: 'please input your loginId' ,
} ) ;
}
} ,
processMessage ( messagePacket ) {
let that = this ;
let msgCommand = messagePacket. command;
switch ( msgCommand) {
case "SYS_NOTIFY_REQUEST" :
that. processSysNotifyPacket ( messagePacket) ;
break ;
case "P2P_MESSAGE_REQUEST" :
that. processP2pMessagePacket ( messagePacket) ;
break ;
default :
console. log ( "msg type to do..." ) ;
}
} ,
processSysNotifyPacket ( notifyPacket ) {
let that = this ;
let notifyType = notifyPacket. notifyType;
switch ( notifyType) {
case "CLIENT_ONLINE" :
that. processUserOnline ( notifyPacket. jsonNotifyInfo) ;
break ;
case "CLIENT_OFFLINE" :
that. processUserOffline ( notifyPacket. jsonNotifyInfo) ;
break ;
default :
console. log ( "process sys notify..." ) ;
}
} ,
processUserOnline ( onlineInfo ) {
let that = this ;
let userObj = JSON . parse ( onlineInfo) ;
let onlineUser = userObj. onlineUser;
if ( that. loginUserId !== onlineUser) {
if ( window. Notification) {
Notification. requestPermission ( function ( status ) {
var n = new Notification ( '上线通知' , { body: '用户:' + userObj. onlineUser + "上线了!" } ) ;
} ) ;
}
}
} ,
processUserOffline ( offlineInfo ) {
let that = this ;
let userObj = JSON . parse ( offlineInfo) ;
let userId = userObj. offlineUser;
if ( that. loginUserId !== onlineUser) {
if ( window. Notification) {
Notification. requestPermission ( function ( status ) {
var n = new Notification ( '下线通知' , { body: '用户:' + userId + "下线了!" } ) ;
} ) ;
}
}
} ,
sendMessage ( ) {
let that = this ;
if ( ! window. WebSocket && ! window. MozWebSocket) {
alert ( "your browser does not support websocket" ) ;
return ;
}
if ( that. socket. readyState === WebSocket. OPEN ) {
if ( that. message2UserId) {
if ( that. isLogined) {
if ( that. messageInfo) {
if ( that. message2UserId !== that. loginUserId) {
that. isSending = true ;
let p2pMessagePacket = { } ;
p2pMessagePacket. dataInfo = {
fromId: that. loginUserId,
toId: that. message2UserId,
messageInfo: that. messageInfo,
} ;
p2pMessagePacket. command = "5" ;
that. chatMessages. push ( p2pMessagePacket. dataInfo) ;
that. socket. send ( JSON . stringify ( p2pMessagePacket) ) ;
that. messageInfo = '' ;
that. scrollMessages2Bottom ( ) ;
that. isSending = false ;
} else {
that. $notification[ 'info' ] ( {
message: 'you can not chat with yourself' ,
} ) ;
}
} else {
that. $notification[ 'info' ] ( {
message: 'chat message can not be empty!' ,
} ) ;
}
} else {
that. $notification[ 'info' ] ( {
message: 'please login before chat to someone!' ,
} ) ;
}
} else {
that. $notification[ 'info' ] ( {
message: 'please input userId which you wanna to chat' ,
} ) ;
}
} else {
console. log ( "WebSocket connect failed" ) ;
}
} ,
processP2pMessagePacket ( messagePacket ) {
let that = this ;
that. chatMessages. push ( messagePacket) ;
that. scrollMessages2Bottom ( ) ;
} ,
scrollMessages2Bottom ( ) {
let that = this ;
let targetEleId = "#chatMessage_" + ( that. chatMessages. length - 1 ) ;
console. log ( "targetEle:" + targetEleId) ;
setTimeout ( function ( ) {
that. $refs. chatMessagesScroller. scrollIntoView ( targetEleId, 100 ) ;
} , 100 ) ;
}
} ,
mounted ( ) {
let that = this ;
that. initSocketConnect ( ) ;
}
}
</ script>
< style scoped >
.index {
width : 60%;
margin : 0 auto;
height : 100%;
margin-top : 60px;
}
.messagesWrapper {
height : 60vh;
background-color : rgba ( 255, 255, 255, .6) ;
border-radius : 4px;
margin-bottom : 20px;
}
.chatMessages {
padding : 20px;
}
.chatMessageItem {
width : 100%;
display : flex;
align-items : flex-start;
}
.chatMessageItem .messageInfo {
width : 0;
flex : 1;
}
.chatMessageItem.send {
flex-direction : row-reverse;
justify-content : flex-end;
}
.chatMessageItem.send .messageAuthor {
margin-left : 10px;
}
.chatMessageItem.send .messageInfo {
text-align : right;
}
.chatMessageItem.receive {
flex-direction : row;
justify-content : flex-start;
}
.chatMessageItem.receive .messageAuthor {
margin-right : 10px;
}
.chatMessageItem.receive .messageInfo {
text-align : left;
}
.chat-bubble {
color : #333;
box-shadow : 3px 5px 15px rgba ( 0, 0, 0, .2) ;
padding : 5px 10px;
width : auto;
max-width : 50%;
text-align : left;
display : inline-block !important ;
position : relative;
word-break : break-all;
background-color : #ffffff;
transition : all .2s;
cursor : pointer;
margin-bottom : 10px;
}
.chat-bubble:hover {
transform : scale ( 1.03) ;
}
.chat-bubble-left {
float : left;
border-radius : 0 5px 5px 5px;
}
.chat-bubble-left:before {
content : '' ;
width : 6px;
height : 6px;
left : -6px;
top : 0;
position : absolute;
border-left : 3px solid transparent;
border-bottom : 3px solid transparent;
border-top : 3px solid #ffffff;
border-right : 3px solid #ffffff;
}
.chat-bubble-right {
float : right;
border-radius : 5px 0 5px 5px;
}
.chat-bubble-right:after {
content : '' ;
width : 6px;
height : 6px;
right : -6px;
top : 0;
position : absolute;
border-left : 3px solid #ffffff;
border-bottom : 3px solid transparent;
border-top : 3px solid #ffffff;
border-right : 3px solid transparent;
}
.chat-bubble-left.chat-bubble-primary {
background : linear-gradient ( 90deg, #2b92e4, #30a1dc) !important ;
color : #ffffff !important ;
}
.chat-bubble-left.chat-bubble-primary:before {
border-right : 3px solid #2b92e4 !important ;
border-top : 3px solid #2b92e4 !important ;
}
.chat-bubble-right.chat-bubble-primary {
background : linear-gradient ( 90deg, #30a1dc, #2b92e4) !important ;
color : #ffffff !important ;
}
.chat-bubble-right.chat-bubble-primary:after {
border-left : 3px solid #2b92e4 !important ;
border-top : 3px solid #2b92e4 !important ;
}
.chat-bubble-left.chat-bubble-success {
background : linear-gradient ( 90deg, #4caf50, #66b869) !important ;
color : #ffffff !important ;
}
.chat-bubble-left.chat-bubble-success:before {
border-right : 3px solid #4caf50 !important ;
border-top : 3px solid #4caf50 !important ;
}
.chat-bubble-right.chat-bubble-success {
background : linear-gradient ( 90deg, #66b869, #4caf50) !important ;
color : #ffffff !important ;
}
.chat-bubble-right.chat-bubble-success:after {
border-left : 3px solid #4caf50 !important ;
border-top : 3px solid #4caf50 !important ;
}
</ style>