//php 后端
<?php
$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);$server->on('open', function (Swoole\WebSocket\Server $server, $request) {//$server->push($request->fd, '欢迎进入我们的聊天室~');
});//接收客户端发送的信息
//$frame 是 Swoole\WebSocket\Frame 对象,包含了客户端发来的数据帧信息
//$frame->fd 代表客户端的唯一标识 客户id
//$frame->data  代表客户端发送的消息
$server->on('message', function (Swoole\WebSocket\Server $server, $frame) {//获取客户端发送的消息$type = json_decode($frame->data,true);if($type['type'] != 'active'){$result['data'] = $frame->data;$types = 1;$framedata = json_decode($frame->data,true);$openid  = $framedata['openid'];$endopenid  = $framedata['endopenid'];$imgtype  = $framedata['imgtype'];$url = 'http://www.xxx.com/';$wxapp = '/app/index.php?i=2&t=0&v=1.01&from=wxapp&c=entry&a=wxapp';// 会话列表创建会话接口$socket_add = '&do=chat_socket_add&m=gc_school&';//会话信息查询接口$socket_find = '&do=chat_socket_find&m=gc_school&';//用户openid 绑定会话 fd 接口$user_fid = '&do=chat_user_find&m=gc_school&';//存储消息记录$socket_log = '&do=socket_log&m=gc_school&';//重置fd为0$socket_isfd = '&do=socket_isfd&m=gc_school&';//查询对方的fd$user_endfind = '&do=chat_user_endfind&m=gc_school&';//查询用户信息$Socket_users = '&do=Socket_users&m=gc_school&';//如果不存在会话id 就去创建会话ID

// var_dump(frame−>relation);die;if(frame->relation);die; if(frame−>relation);die;if(framedata[‘relation’]){
usess=′ids=′.usess = 'ids='.usess=′ids=′.framedata[‘relation’];
//如果存在会话id就去查询会话id的信息
$relation_url = url.url.url.wxapp.socketfind.socket_find.socketf​ind.usess;
relationdata=filegetcontents(relationdata = file_get_contents(relationdata=fileg​etc​ontents(relation_url); // 查询会话信息
}else{
usess=′openid=′.usess = 'openid='.usess=′openid=′.openid.‘&endopenid=’.$endopenid;
//拼接创建会话id信息并请求接口
$relation_url = url.url.url.wxapp.socketadd.socket_add.socketa​dd.usess;
relationdata=filegetcontents(relationdata = file_get_contents(relationdata=fileg​etc​ontents(relation_url); // 建立会话信息
}
jsonfd=jsondecode(json_fd = json_decode(jsonf​d=jsond​ecode(relationdata,true);
//openid 和 fd 一起查询,以当前的fd为准每次发消息
if($openid){
fddata=′relation=′.fddata = 'relation='.fddata=′relation=′.json_fd[‘data’][‘id’].‘&fd=’.KaTeX parse error: Expected 'EOF', got '&' at position 12: frame->fd.'&̲openid='.openid;
$relationurlfd = url.url.url.wxapp.userfid.user_fid.userf​id.fddata;
userfd=filegetcontents(user_fd = file_get_contents(userf​d=fileg​etc​ontents(relationurlfd); // fd信息
}
//查询对方的fd
if($openid){
endfddata=′relation=′.endfddata = 'relation='.endfddata=′relation=′.json_fd[‘data’][‘id’].‘&fd=’.KaTeX parse error: Expected 'EOF', got '&' at position 12: frame->fd.'&̲openid='.openid;
$endrelationurlfd = url.url.url.wxapp.userendfind.user_endfind.usere​ndfind.endfddata;
enduserfd=filegetcontents(enduser_fd = file_get_contents(enduserf​d=fileg​etc​ontents(endrelationurlfd); // fd信息
}
endre=jsondecode(endre = json_decode(endre=jsond​ecode(enduser_fd,true);
// file_get_contents($url);
// file_get_contents();
re=jsondecode(re = json_decode(re=jsond​ecode(user_fd,true);
content=jsondecode(content = json_decode(content=jsond​ecode(frame->data,true);
socketlogdata=′relation=′.socket_logdata = 'relation='.socketl​ogdata=′relation=′.json_fd[‘data’][‘id’].‘&content=’.KaTeX parse error: Expected 'EOF', got '&' at position 21: …nt['content'].'&̲type='.framedata[‘typess’].‘&openid=’.KaTeX parse error: Expected 'EOF', got '&' at position 9: openid.'&̲endopenid='.endopenid.‘&imgtype=’.imgtype;//添加聊天记录if(imgtype; // 添加聊天记录 if(imgtype;//添加聊天记录if(type[‘type’] != ‘active’){
$relationurl = url.url.url.wxapp.socketlog.socket_log.socketl​og.socket_logdata;
file_get_contents($relationurl); // fd
}

        //查询用信息$fds = 'openid='.$openid;$users = $url.$wxapp.$Socket_users.$fds;$udata = file_get_contents($users);$uc = json_decode($udata,true);$content['users'] = $uc['data'];

// re=jsondecode(re = json_decode(re=jsond​ecode(result[‘data’],true);
// $re[‘users’] = $content;
result[′data′]=jsonencode(result['data'] = json_encode(result[′data′]=jsone​ncode(content);
// $result[‘data’][‘users’] = $content;
$data = [
‘msg’ => ‘操作成功’,
‘data’ => $result,
‘fd’ => frame−>fd,′errorcode′=>0,′types′=>frame->fd, 'error_code' => 0, 'types'=>frame−>fd,′errorc​ode′=>0,′types′=>types,
‘imgtype’=>$imgtype,

        ];// 检测fd 是否在线if ($server->isEstablished($endre['data']['fd'])) {$server->push($frame->fd, json_encode($data)); // 推给自己$server->push($endre['data']['fd'], json_encode($data)); // 推给对方}else{$fds = 'ids='.$endre['data']['id'];$isfd = $url.$wxapp.$socket_isfd.$fds;file_get_contents($isfd); // 推送对方用户不在线重置fd为0$server->push($frame->fd, json_encode($data)); // 推给自己}}else{$types = 0;$data = ['msg' => '操作成功','data' => [],'fd' => $frame->fd,'error_code' => 0,'types'=>$types,];$server->push($frame->fd, json_encode($data)); // 定时任务推送自己防止断线}});$server->on('close', function ($ser, $fd) {echo "client {$fd} closed\n";
});$server->start();

//具体消息接口这些东西需要自行写入目前逻辑仅代表个人观点 每次修改切记运行下php文件(不是访问切记)

宝塔反向代理
upstream websocket{
hash KaTeX parse error: Expected 'EOF', got '}' at position 87: …l_timeout=30s; }̲ server { list… https://$host$1 permanent;
}
server
{
# listen 80;
listen 443 ssl http2;
server_name socket.flyccampus.com;
index index.php index.html index.htm default.php default.htm default.html;
root /www/wwwroot/socket.flyccampus.com;

#SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
#error_page 404/404.html;
ssl_certificate    /www/server/panel/vhost/cert/socket.flyccampus.com/fullchain.pem;
ssl_certificate_key    /www/server/panel/vhost/cert/socket.flyccampus.com/privkey.pem;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header Strict-Transport-Security "max-age=31536000";
error_page 497  https://$host$request_uri;#SSL-END#ERROR-PAGE-START  错误页配置,可以注释、删除或修改
#error_page 404 /404.html;
#error_page 502 /502.html;
#ERROR-PAGE-END#PHP-INFO-START  PHP引用配置,可以注释或修改
#清理缓存规则

location / {
if (!-e KaTeX parse error: Expected '}', got '#' at position 26: …lename) { #̲一级目录 rewri… /index.php?s=$1 last;
break;
}
#wss配置
client_max_body_size 100m;
proxy_redirect off;
proxy_set_header Host $host;# http请求的主机域名
proxy_set_header X-Real-IP $remote_addr;# 远程真实IP地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;#反向代理之后转发之前的IP地址
proxy_read_timeout 604800s;#websocket心跳时间,默认是60s
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “Upgrade”;

 proxy_pass http://websocket;#反向代理转发地址}location ~ /purge(/.*) {proxy_cache_purge cache_one $host$1$is_args$args;#access_log  /www/wwwlogs/socket.flyccampus.com_purge_cache.log;
}
#引用反向代理规则,注释后配置的反向代理将无效
include /www/server/panel/vhost/nginx/proxy/socket.flyccampus.com/*.conf;include enable-php-00.conf;
#PHP-INFO-END#REWRITE-START URL重写规则引用,修改后将导致面板设置的伪静态规则失效
include /www/server/panel/vhost/rewrite/socket.flyccampus.com.conf;
#REWRITE-END#禁止访问的文件或目录
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
{return 404;
}#一键申请SSL证书验证目录相关设置
location ~ \.well-known{allow all;
}access_log  /www/wwwlogs/socket.flyccampus.com.log;
error_log  /www/wwwlogs/socket.flyccampus.com.error.log;

}

//前端代码
utils/config.js
module.exports = {

// 请求域名 格式: https://您的域名
HTTP_REQUEST_URL:‘http://socket.flyccampus.com’,
// Socket链接 暂不做配置
WSS_SERVER_URL:‘wss://xxx.com’,
//JWT token 名称
TOKEN_NAME:‘token’,
//用户注册id 名称
USER_ID:‘uid’,
//用户注册openid 名称
OPEN_ID:‘openid’,
// 以下配置非开发者,无需修改
// 请求头
HEADER:{
‘content-type’: ‘application/json’
},

}
utils/websocket.js

import {WSS_SERVER_URL} from “config.js”

//定时标识
let timing = false

function connect(user, func) {
wx.connectSocket({
url: ${WSS_SERVER_URL}?type=ask&fid=${user.id}&tid=100,
header: { ‘content-type’: ‘application/json’ },
success: function () {
console.log(‘websocket连接成功~’)
},
fail: function () {
console.log(‘websocket连接失败~’)
}
})
wx.onSocketOpen(function (res) {
// wx.showToast({
// title: ‘websocket已开通~’,
// icon: “success”,
// duration: 2000
// })
//接受服务器消息
wx.onSocketMessage(func);//func回调可以拿到服务器返回的数据
});

//启动心跳包
linkWebsocketXin(40000, true)

wx.onSocketError(function (res) {
wx.showToast({
title: ‘websocket连接失败,请检查!’,
icon: “none”,
duration: 1000
})
})
}
//心跳包
function linkWebsocketXin(time, status) {
if (status == true) {
timing = setInterval(function () {
console.log(“当前心跳已重新连接”);
//循环执行代码
wx.sendSocketMessage({
data: JSON.stringify({
type: ‘active’,
}),
fail(res) {
// console.log(res)
}
});
}, time) //循环时间,注意不要超过1分钟
} else {
//关闭定时器
clearInterval(timing);
console.log(“当前心跳已关闭”);
}
}
//发送消息
function send(msg) {
//关闭心跳包定时器
linkWebsocketXin(40000, false)
wx.sendSocketMessage({
data: msg,
success:res=>{
//重启心跳包
linkWebsocketXin(40000, true)
}
});
}
module.exports = {
connect: connect,
send: send,
linkWebsocketXin:linkWebsocketXin
}

utils/util.js

const formatTime = date => {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()

return ${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}
}

const formatNumber = n => {
n = n.toString()
return n[1] ? n : 0${n}
}

module.exports = {
formatTime
}

/聊天列表
chat.js
const app = getApp()
var websocket = require(‘…/…/…/utils/websocket.js’);
var utils = require(‘…/…/…/utils/util.js’);

import {HTTP_REQUEST_URL, HEADER, USER_ID, OPEN_ID} from “…/…/…/utils/config.js”

Page({
/**

  • 页面的初始数据
    /
    data: {
    newslist: [],
    userInfo: {},
    scrollTop: 0,
    increase: false,//图片添加区域隐藏
    aniStyle: true,//动画效果
    message: “”,
    previewImgList: [],
    relation:0, // 会话id
    openid:‘’,
    endopenid:‘’,
    img:‘’,
    imgtype:0,
    toView:‘msg-0’,
    top:0,
    pages:1,
    moban:‘’
    },
    /
    *

  • 生命周期函数–监听页面加载
    */
    onLoad: function (options) {
    this.getfd()
    this.getmoban()
    this.setData({
    openid: wx.getStorageSync(‘openid’) // 本用户的openid
    })
    if(options.relation){ // 如果有会话id
    this.setData({
    relation: options.relation // 赋值会话id
    })
    this.getlist()
    }
    if(this.data.relation == 0){
    this.setData({
    endopenid: options.openid // 赋值需要聊天人的openid
    })
    this.getrelation()
    }

    var that = this
    if (app.globalData.userInfo) {
    this.setData({
    userInfo: app.globalData.userInfo
    })
    }
    //调通接口
    websocket.connect(this.data.userInfo, function (res) {
    console.log(res,‘—’)
    var list = []
    list = that.data.newslist
    var data = JSON.parse(res.data)
    console.log(data.types,‘datatype----’)
    if(data.types != 0) {
    var datas = JSON.parse(data.data.data)
    console.log(datas.content,‘data----’)
    // list = datas.content
    // } else {
    list.push(datas)
    }
    that.setData({
    newslist: list
    })
    // that.bottom()
    })

},
// 页面卸载
onUnload() {

wx.closeSocket();
// wx.showToast({
//   title: '连接已断开~',
//   icon: "none",
//   duration: 2000
// })

},
onPullDownRefresh(){
console.log(111)
this.getpagedata()
},
getrelation(){
var that = this;
app.util.request({
url: ‘entry/wxapp/socket_users_socket’,
data: {
openid:that.data.openid,
endopenid:that.data.endopenid
},
success(res) {
console.log(res.data.data,‘—lll—’)
if(res.data.errno == 0){
that.setData({
relation: res.data.data.id // 赋值会话id
})
that.getlist()
}

  }
})

},
//加载历史消息
getpagedata(){
var that = this;
app.util.request({
url: ‘entry/wxapp/socket_user_log’,
data: {
openid:that.data.openid,
relation:that.data.relation,
page:that.data.pages
},
success(res) {
console.log(res.data.data,‘—lll—’)
that.setData({
newslist: [
…res.data.data,
…that.data.newslist
],
// newslist:res.data.data,
pages:that.data.pages+=1
})
// setTimeout(()=>{
// that.pageScrollToBottom();
// },500)
}
})
},
getfd(){
let msg = {
type:‘active’,//咨询
openid:this.data.openid,
endopenid:this.data.endopenid,
relation:this.data.relation // 会话id
};
websocket.send(JSON.stringify(msg))
},
//图片上传
choose()
{
wx.chooseImage({
count: 1,
sizeType: [‘original’, ‘compressed’], //可以指定是原图还是压缩图,默认二者都有
sourceType: [‘album’], //从相册选择
success: (res) => {
console.log(‘path’,res)
this.uploads(res)

      }})},uploads(res) {var that = this;wx.showLoading({title: '上传中',})wx.uploadFile({url: app.util.url() + 'c=entry&a=wxapp&do=ImgPost&m=gc_school', // 仅为示例,非真实的接口地址filePath: res.tempFilePaths[0],header: {'content-type': 'application/x-www-form-urlencoded'},name: 'file',success: (result) => {wx.hideLoading()var resu = JSON.parse(result.data)console.log(resu)if(resu.errno==0){that.setData({img:resu.data})that.setData({imgtype:1})that.send()}else{wx.showToast({title: resu.message,icon:'none'})}}})},

getlist(){
var that = this;
app.util.request({
url: ‘entry/wxapp/socket_user_log’,
data: {
openid:that.data.openid,
relation:that.data.relation,
page:that.data.pages
},
success(res) {
console.log(res.data.data,‘—lll—’)
that.setData({
newslist:res.data.data,
pages:2
})
setTimeout(()=>{
that.pageScrollToBottom();
},1000)
}
})
},
//图片预览
preview(e)
{
// this.setData({
// freshen:false
// })
console.log(e.currentTarget.dataset.index,‘—’)
var content = this.data.newslist[e.currentTarget.dataset.index].content;
console.log(content,‘—’)
wx.previewImage({
current:content,
urls: [content],
})
},
//事件处理函数
send: function () {
var flag = this
let uid = wx.getStorageSync(USER_ID)
if(this.data.img.trim() == “” && this.data.imgtype == 1){
wx.showToast({
title: ‘图片不能为空哦~’,
icon: “none”,
duration: 2000
})
return
}

if (this.data.message.trim() == "" && this.data.imgtype == 0) {wx.showToast({title: '消息不能为空哦~',icon: "none",duration: 2000})return
}setTimeout(function () {flag.setData({increase: false})}, 1000)if(flag.data.imgtype == 1){var msg = {content:this.data.img,date:utils.formatTime(new Date()),type:'ask',//咨询fid:uid,imgtype:1,tid:100,openid:this.data.openid,endopenid:this.data.endopenid,relation:this.data.relation // 会话id
};}else{var msg = {content:this.data.message,date:utils.formatTime(new Date()),type:'ask',//咨询fid:uid,imgtype:0,tid:100,openid:this.data.openid,endopenid:this.data.endopenid,relation:this.data.relation // 会话id
};}flag.setData({imgtype: 0})websocket.send(JSON.stringify(msg))/*websocket.send('{ "content": "' + this.data.message + '", "date": "' + utils.formatTime(new Date()) + '","type":"text", "nickName": "' + this.data.userInfo.nickName + '", "avatarUrl": "' + this.data.userInfo.avatarUrl + '" }')*///发完消息值改为空this.setData({message: '',
})setTimeout(()=>{flag.pageScrollToBottom();},1000)// this.bottom()

},
//监听input值的改变
bindChange(res) {
this.setData({
message: res.detail.value
})
},
cleanInput() {
//button会自动清空,所以不能再次清空而是应该给他设置目前的input值
this.setData({
message: this.data.message
})
},
increase() {
this.setData({
increase: true,
aniStyle: true
})
},
//点击空白隐藏message下选框
outbtn() {
this.setData({
increase: false,
aniStyle: true
})
},
//发送图片
chooseImage() {
var that = this
wx.chooseImage({
count: 1, // 默认9
sizeType: [‘original’, ‘compressed’], // 可以指定是原图还是压缩图,默认二者都有
sourceType: [‘album’, ‘camera’], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
// 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
var tempFilePaths = res.tempFilePaths
// console.log(tempFilePaths)
wx.uploadFile({
url: ‘wss://www.xxx.cn’, //服务器地址
filePath: tempFilePaths[0],
name: ‘file’,
headers: {
‘Content-Type’: ‘form-data’
},
success: function (res) {
if (res.data) {
that.setData({
increase: false
})
websocket.send(‘{“images”:"’ + res.data + ‘“,“date”:”’ + utils.formatTime(new Date()) + ‘“,“type”:“image”,“nickName”:”’ + that.data.userInfo.nickName + ‘“,“avatarUrl”:”’ + that.data.userInfo.avatarUrl + ‘"}’)
that.bottom()
}
}
})
}
})
},
//图片预览
previewImg(e) {
var that = this
//必须给对应的wxml的image标签设置data-set=“图片路径”,否则接收不到
var res = e.target.dataset.src
var list = this.data.previewImgList //页面的图片集合数组
//判断res在数组中是否存在,不存在则push到数组中, -1表示res不存在
if (list.indexOf(res) == -1) {
this.data.previewImgList.push(res)
}
wx.previewImage({
current: res, // 当前显示图片的http链接
urls: that.data.previewImgList // 需要预览的图片http链接列表
})
},
//聊天消息始终显示最底端
bottom: function () {
this.setData({
message: ‘’,
})
var query = wx.createSelectorQuery()
query.select(‘#flag’).boundingClientRect()
query.selectViewport().scrollOffset()
query.exec(function (res) {
wx.pageScrollTo({
scrollTop: res[0].bottom // #the-id节点的下边界坐标
})
res[1].scrollTop // 显示区域的竖直滚动位置
})
},
pageScrollToBottom: function() {
wx.createSelectorQuery().select(‘#flag’).boundingClientRect(function(rect){
// 使页面滚动到底部
wx.pageScrollTo({
scrollTop: rect.bottom
})
}).exec()
},
getmoban(){
var that = this;
app.util.request({
url: ‘entry/wxapp/template_comment’,
data: {
},
success(res) {
console.log(res.data.data,‘—lll—’)
if(res.data.errno == 0){
that.setData({
moban: res.data.data.template_comment // 赋值会话id
})
that.getlist()
}

  }
})

},
ticing(){

console.log("弹出框")
var self = this;
// self.chuo()wx.getSetting({withSubscriptions:true,success (res) {console.log("设置",res)console.log(res.subscriptionsSetting)}})wx.requestSubscribeMessage({tmplIds: [self.data.moban], // 此处可填写多个模板 ID,但低版本微信不兼容只能授权一个success (res) {self.chuo()}})

},
chuo(){
var that = this;
app.util.request({
url: ‘entry/wxapp/tsuisong’,
data: {
‘openid’:that.data.openid,
‘relation’:that.data.relation
},
success(res) {
console.log(res.data.data,‘—lll—’)
if(res.data.errno == 0){
that.setData({
moban: res.data.data.template_comment // 赋值会话id
})
that.getlist()
}

  }
})

}
})
chat.json
{
“usingComponents”: {},
“enablePullDownRefresh”: true
}
chat.wxml

返回聊天

{{item.content}} {{item.date}} {{item.content}}

<view class="date">{{item.date}}</view>

发送

chat.wxss
/* pages/socks/socks.wxss */
page {
background-color: #f7f7f7;
height: 100%;
}

/* 聊天内容 /
.news {
padding-top: 30rpx;
text-align: center;
/
height:100%; */
box-sizing: border-box;
}

#flag {
margin-bottom: 100rpx;
height: 30rpx;
}

.chat-notice {
text-align: center;
font-size: 30rpx;
padding: 10rpx 0;
color: #666;
}

.historycon {
height: 100%;
width: 100%;
/* flex-direction: column; */
display: flex;
border-top: 0px;
}

/* 聊天 */
.chat-news {
width: 100%;
overflow: hidden;
}

.chat-news .my_right {
float: right;
/* right: 40rpx; */
padding: 10rpx 10rpx;
}

.chat-news .name {
margin-right: 10rpx;
}

.chat-news .you_left {
float: left;
/* left: 5rpx; */
padding: 10rpx 10rpx;
}

.selectImg {
display: inline-block;
width: 150rpx;
height: 150rpx;
margin-left: 50rpx;
}

.my_right .selectImg {
margin-right: 80rpx;
}

.new_img {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
vertical-align: middle;
margin-right: 10rpx;
}

.new_txt {
max-width: 300rpx;
display: inline-block;
border-radius: 6rpx;
line-height: 60rpx;
background-color: #95d4ff;
padding: 5rpx 20rpx;
margin: 0 10rpx;
margin-left: 50rpx;
}

.my_right .new_txt {
margin-right: 60rpx;
}

.you {
background-color: lightgreen;
}

.my {
border-color: transparent transparent transparent #95d4ff;
}

.you {
border-color: transparent #95d4ff transparent transparent;
}

.hei {
margin-top: 50px;
height: 20rpx;
}

.history {
height: 100%;
margin-top: 15px;
padding: 10rpx;
font-size: 14px;
line-height: 40px;
word-break: break-all;
}

::-webkit-scrollbar {
width: 0;
height: 0;
color: transparent;
z-index: -1;
}

/* 信息输入区域 */
.message {
position: fixed;
bottom: 0;
width: 100%;
}

.sendMessage {

height: 80rpx;
padding: 10rpx 10rpx;
background-color: #fff;
border-top: 2rpx solid #eee;
border-bottom: 2rpx solid #eee;
/z-index: 3;/
}

.sendMessage input {
float: left;
height: 42px;
line-height: 100%;
border-bottom: 1rpx solid #ccc;
padding: 0 10rpx;
font-size: 35rpx;
color: #666;
}

.sendMessage button {
float: right;
font-size: 35rpx;
}

.sendMessage view {
display: inline-block;
width: 80rpx;
height: 80rpx;
line-height: 80rpx;
font-size: 60rpx;
text-align: center;
color: #999;
border: 1rpx solid #ccc;
border-radius: 50%;
margin-left: 10rpx;
}

.increased {
width: 100%;
/* height: 150rpx; */
padding: 40rpx 30rpx;
background-color: #fff;
}

.increased .image {
width: 100rpx;
height: 100rpx;
border: 3rpx solid #ccc;
line-height: 100rpx;
text-align: center;
border-radius: 8rpx;
font-size: 35rpx;
}

@keyframes slidedown {
from {
transform: translateY(0);
}

to {
transform: translateY(100%);
}
}

.slidedown {
animation: slidedown 0.5s linear;
}

.slideup {
animation: slideup 0.5s linear;
}

@keyframes slideup {
from {
transform: translateY(100%);
}

to {
transform: translateY(0);
}
}

前端采用colorui样式插件
完成示例图

///注意会话列表是自己写的

有啥问题加我微信或者QQ1446891130 看到有空给你说一下

WebSocket私信聊天(无群聊天)相关推荐

  1. 手机浏览器打开QQ聊天和群聊天

    普通QQ mqqwpa://im/chat?chat_type=wpa&uin=${qq}&version=1&src_type=web&web_src=oicqzon ...

  2. websocket以及nodejs联手打造的类qq群聊天室 教程 附 原代码

    这次给大家分享的是我自己开发的多人聊天室,利用websocket 以及服务器端使用node.js 来让用户不需要刷新浏览器就可以获得实时更新. 如下面图所示的样子.开发出类QQ群聊天室的主界面,当然U ...

  3. 集群聊天服务器项目(四)——项目总结

    集群聊天服务器项目总结 首先是就是项目介绍集群聊天服务器项目(零)--项目介绍中的内容,就不再次copy过来了 项目简单介绍 技术栈 环境和库依赖 按模块介绍整个项目 程序的主要模块是网络模块.业务模 ...

  4. 跟着源码一起学:手把手教你用WebSocket打造Web端IM聊天

    本文作者芋艿,原题"芋道 Spring Boot WebSocket 入门",本次有修订和改动. 一.引言 WebSocket如今在Web端即时通讯技术应用里使用广泛,不仅用于传统 ...

  5. HTML5 之WebSocket入门demo和简易聊天室

    HTML5 WebSocket WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议. 在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏 ...

  6. Java基于Socket实现聊天、群聊、敏感词汇过滤功能

    首先的话,这个代码主要是我很久以前写的,然后当时还有很多地方没有理解,现在再来看看这份代码,实在是觉得丑陋不堪,想改,但是是真的改都不好改了- 所以,写代码,规范真的很重要. 实现的功能: 用户私聊 ...

  7. springboot和netty整合的聊天室--群聊

    一.创建项目 file-new-project-spring initializr-next 然后 添加这两个依赖 二.代码 DemoApplication package com.example.d ...

  8. 基于Tomcat7、Java、WebSocket的服务器推送聊天室

    2019独角兽企业重金招聘Python工程师标准>>> 基于Tomcat7.Java.WebSocket的服务器推送聊天室 转载于:https://my.oschina.net/u/ ...

  9. C++搭建集群聊天室(十四):群聊功能

    文章目录 群聊功能思路 放码过来 groupuser.hpp group.hpp groupmodel.hpp groupmodel.cpp 群聊功能思路 1.创建群聊,提交群信息,返回群号 2.拉取 ...

最新文章

  1. 在python中、下列代码的输出是什么-python面试题详细总结(附答案)
  2. 一个产品经理的自述:我在腾讯工作的这一年(转)
  3. RocksDB 6.0.2 发布,Facebook 推出的存储系统
  4. ASP.NET Core HTTP 管道中的那些事儿
  5. linux网络编程(一)网络基础传输知识
  6. ElasticSearch 2 (27) - 信息聚合系列之故事开始
  7. HTTP 和 HTTPS 两种传输协议各自含义是什么?二者使用有什么区别?
  8. redis cluster管理工具redis-trib.rb详解
  9. [软件工程学习笔记]个人java小程序---词频统计(二)
  10. CCF CSP202006-1 线性分类器
  11. isis协议_[IS-IS] IS-IS路由协议的基本知识及配置
  12. 51单片机(十)—— 8位数码管-数码管扫描
  13. R语言伴随矩阵的计算
  14. iView的表格做一个带斜线的表头
  15. hdu 1880 魔咒词典 (字符串哈希)
  16. 具有生物启发训练方法的物理深度学习:物理硬件的无梯度方法
  17. 不可见字符和表情包正则
  18. 读《大数据之路-阿里巴巴大数据实践》数据模型篇笔记
  19. 移动创维E900V21C救砖过程,附线刷刷机固件
  20. 杰理之杰理音箱方案选型【篇】

热门文章

  1. 国产软件爆发!中国版Navicat,SQL Studio成数据库管理工具热门
  2. C# Nut Shell 第九章 LINQ运算符
  3. python聊天室详细教程_python简单实现聊天室功能(代码教程)
  4. ***WAAAAA***
  5. WPF验证身份证准确性
  6. 前淘宝工程师对12306的解读: 曾嗤之以鼻 现在认为几乎是奇迹
  7. 在wps里面怎么设置触发器_WPS演示触发器的使用(一)
  8. wps js宏开发表格数据归类拆分和excel文件合并的xlam加载宏插件
  9. pixar动画短片集
  10. 数据库的应用(政务云一 )