详解微信小程序开发聊天室—实时聊天,支持图片预览


Posted in Javascript onMay 20, 2019

第一次写小程序,老板就让我用websoket写个聊天对话,群聊这种。第一次写聊天功能,第一次用websoket,第一次用小程序,这是在考验我吗?不过我还是研究了一下,终于实现了。

首先看一下界面,界面很简单,就是首页刚进来获取了用户信息头像,昵称等。点击进入聊天室就可以聊天了,下面我介绍的是前端代码实现,后台需要做的很简单,就是你给他发送什么数据,他就给你返回什么数据,就是在接收前台发送过来的图片的时候需要做个格式转换,因为有时候前端将接收到的json字符串转换json对象的时候,遇到有特殊的标点符号可能会报错,比如我就是‘\'报的错,找了半天。

因为有人咨询,所以附上所有小程序代码,地址:https://github.com/chongwenwen/weixin_chat/tree/master

有人说为什么没有utile.js的代码,这个功能只用到websoket.js跟utile.js没有关系哦!还有后台代码在页面最底下

详解微信小程序开发聊天室—实时聊天,支持图片预览         详解微信小程序开发聊天室—实时聊天,支持图片预览

详解微信小程序开发聊天室—实时聊天,支持图片预览        详解微信小程序开发聊天室—实时聊天,支持图片预览

文档目录结构如下:(聊天页面为chat)

详解微信小程序开发聊天室—实时聊天,支持图片预览  

chat.wxml页面

首先写好页面结构,既然是群聊功能,肯定有自己和别人,所以页面的view盒子应给有两部分,一个内容左侧显示,一个内容右侧显示,下面是代码,因为没有正式注册企业项目,我用的服务器都是本地的服务器,所以界面区分别人和我的聊天信息是用昵称区分的,如果正式项目应该是由一个用户标记去区分的

<view class="news" bindtap='outbtn'>
 
<view class="chat-notice" wx:if="{{userInfo}}">系统消息: 欢迎 {{ userInfo.nickName }} 加入群聊</view>
 
<view class="historycon">
 
<scroll-view scroll-y="true" class="history" scroll-top="{{scrollTop}}">
 
<block wx:for="{{newslist}}" wx:key>
 
    <!-- 历史消息 -->
 
<!-- <view class="chat-news">
<view style="text-align: left;padding-left: 20rpx;">
<image class='new_img' src="{{item.avatarUrl? item.avatarUrl:'images/avator.png'}}"></image>
<text class="name">{{ item.nickName }}{{item.date}}</text>
</view>
<view class='you_left'>
<block wx:if="{{item.type=='text'}}">
<view class='new_txt'>{{item.content}}</view>
</block>
<block wx:if="{{item.type=='image'}}">
<image class="selectImg" src="{{item.images}}"></image>
</block>
</view>
</view> -->
 
<view>{{item.date}}</view>
 
<!--自己的消息 -->
 
<view class="chat-news" wx:if="{{item.nickName == userInfo.nickName}}">
 
<view style="text-align: right;padding-right: 20rpx;">
 
<text class="name">{{ item.nickName }}</text>
 
<image class='new_img' src="{{userInfo.avatarUrl}}"></image>
 
</view>
 
<view class='my_right'>
 
<block wx:if="{{item.type=='text'}}">
 
<view class='new_txt'>{{item.content}}</view>
 
</block>
 
<block wx:if="{{item.type=='image'}}">
 
<image class="selectImg" src="{{item.images}}" data-src="{{item.images}}" lazy-load="true" bindtap="previewImg"></image>
 
</block>
 
</view>
 
</view>
 
<!-- 别人的消息 -->
 
<view class="chat-news" wx:else>
 
<view style="text-align: left;padding-left: 20rpx;">
 
<image class='new_img' src="{{item.avatarUrl? item.avatarUrl:'images/avator.png'}}"></image>
 
<text class="name">{{ item.nickName }}</text>
 
</view>
 
<view class='you_left'>
 
<block wx:if="{{item.type=='text'}}">
 
<view class='new_txt'>{{item.content}}</view>
 
</block>
 
<block wx:if="{{item.type=='image'}}">
 
<image class="selectImg" src="{{item.images}}" data-src="{{item.images}}" lazy-load="true" bindtap="previewImg"></image>
 
</block>
 
</view>
 
</view>
 
</block>
 
</scroll-view>
 
</view>
 
</view>
 
<view id="flag"></view>
 
<!-- 聊天输入 -->
 
<view class="message">
 
<form bindreset="cleanInput" class="sendMessage">
 
<input type="text" placeholder="请输入聊天内容.." value="{{massage}}" bindinput='bindChange'></input>
 
<view class="add" bindtap='increase'>+</view>
 
<button type="primary" bindtap='send' formType="reset" size="small" button-hover="blue">发送</button>
 
</form>
 
<view class='increased {{aniStyle?"slideup":"slidedown"}}' wx:if="{{increase}}">
 
<view class="image" bindtap='chooseImage'>相册 </view>
 
</view>
 
</view>

websoket.js文件

在utils目录下,是封装了websoket的请求过程,以便在chat.js中调用。需要注意的是wx.connectSocket代表客户端首次和服务器建立联系,wx.onSocketOpen才是正式打开通道,wx.onSocketMessage必须在 wx.onSocketOpen 回调之后发送才生效。

wx.onSocketMessage里面带有参数是一个函数回调,这个回调就是后台服务器实时接收并返给前台的数据

var url = 'ws://........';//服务器地址
 
 
 
function connect(user,func) {
 
wx.connectSocket({
 
url: url,
 
header:{'content-type': 'application/json'},
 
success: function () {
 
console.log('信道连接成功~')
 
},
 
fail: function () {
 
console.log('信道连接失败~')
 
}
 
})
 
wx.onSocketOpen(function (res) {
 
wx.showToast({
 
title: '信道已开通~',
 
icon: "success",
 
duration: 2000
 
})
 
//接受服务器消息
 
wx.onSocketMessage(func);//func回调可以拿到服务器返回的数据
 
});
 
wx.onSocketError(function (res) {
 
wx.showToast({
 
title: '信道连接失败,请检查!',
 
icon: "none",
 
duration: 2000
 
})
 
})
 
}
 
//发送消息
 
function send(msg) {
 
wx.sendSocketMessage({
 
data: msg
 
});
 
}
 
module.exports = {
 
connect: connect,
 
send: send
 
}

chat.js文件

聊天室的逻辑操作页面,websocket.connect(){}调用的是websocket.js封装好的websoket的逻辑函数,回调就是后台的数据,之所以在本页面调用就是方便接收以后的逻辑操作。我建立文件的时候用的就是微信官方的快速模板生成的,所以app.js里面没有变动,用户在chat.js获取userInfo的时候可以引用全局的app.globalData.userInfo

详解微信小程序开发聊天室—实时聊天,支持图片预览

 还有要注意的一点就是在选择发送图片的时候,必须是先把本地的图片地址发送给后台,转换成服务器的图片地址再次通过wensoket.send发送给服务器,这个时候服务器推送给其他用户的才是正确的地址,否则你的本地地址其他用户是访问不到的。

// pages/chat/chat.js
 
const app = getApp()
 
var websocket = require('../../utils/websocket.js');
 
var utils = require('../../utils/util.js');
 
Page({
 
 
 
/**
* 页面的初始数据
*/
 
data: {
 
newslist:[],
 
userInfo: {},
 
scrollTop: 0,
 
increase:false,//图片添加区域隐藏
 
aniStyle: true,//动画效果
 
message:"",
 
previewImgList:[]
 
},
 
/**
* 生命周期函数--监听页面加载
*/
 
onLoad: function () {
 
var that = this
 
if (app.globalData.userInfo) {
 
this.setData({
 
userInfo: app.globalData.userInfo
 
})
 
}
 
//调通接口
 
websocket.connect(this.data.userInfo, function (res) {
 
// console.log(JSON.parse(res.data))
 
var list = []
 
list = that.data.newslist
 
list.push(JSON.parse(res.data))
 
that.setData({
 
newslist: list
 
})
 
})
 
},
 
// 页面卸载
 
onUnload(){
 
wx.closeSocket();
 
wx.showToast({
 
title: '连接已断开~',
 
icon: "none",
 
duration: 2000
 
})
 
},
 
//事件处理函数
 
send: function () {
 
var flag = this
 
if (this.data.message.trim() == ""){
 
wx.showToast({
 
title: '消息不能为空哦~',
 
icon: "none",
 
duration: 2000
 
})
 
}else {
 
setTimeout(function(){
 
flag.setData({
 
increase: false
 
})
 
},500)
 
websocket.send('{ "content": "' + this.data.message + '", "date": "' + utils.formatTime(new Date()) + '","type":"text", "nickName": "' + this.data.userInfo.nickName + '", "avatarUrl": "' + this.data.userInfo.avatarUrl+'" }')
 
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: 'http://.....', //服务器地址
 
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 () {
 
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 // 显示区域的竖直滚动位置
 
})
 
},
 
})

最后是页面的样式文件chat.wxss

/* pages/chat/chat.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{
 
display: block;
 
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;
 
width: 66%;
 
height: 100%;
 
line-height: 80rpx;
 
border-bottom: 1rpx solid #ccc;
 
padding:0 10rpx;
 
font-size: 35rpx;
 
color: #666;
 
}
 
.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;
 
}
 
.sendMessage button {
 
float: right;
 
font-size: 35rpx;
 
}
 
.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);
 
}
 
}

后台代码(图片):

详解微信小程序开发聊天室—实时聊天,支持图片预览

以上所述是小编给大家介绍的微信小程序实时聊天支持图片预览详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
几个比较实用的JavaScript 测试及效验工具
Apr 18 Javascript
jquery根据锚点offset值实现动画切换
Sep 11 Javascript
node.js+Ajax实现获取HTTP服务器返回数据
Nov 26 Javascript
jQuery调取jSon数据并展示的方法
Jan 29 Javascript
微信小程序之小豆瓣图书实例
Nov 30 Javascript
聊聊JavaScript如何实现继承及特点
Apr 07 Javascript
javascript  数组排序与对象排序的实例
Jul 17 Javascript
npm 更改默认全局路径以及国内镜像的方法
May 16 Javascript
JavaScript实现的简单Tab点击切换功能示例
Jul 06 Javascript
JS实现匀速与减速缓慢运动的动画效果封装示例
Aug 27 Javascript
jquery实现弹窗(系统提示框)效果
Dec 10 jQuery
在JavaScript中查找字符串中最长单词的三种方法(推荐)
Jan 18 Javascript
Vee-validate 父组件获取子组件表单校验结果的实例代码
May 20 #Javascript
React如何实现浏览器打印部分内容详析
May 19 #Javascript
koa-router路由参数和前端路由的结合详解
May 19 #Javascript
Vue.js中该如何自己维护路由跳转记录
May 19 #Javascript
利用Vue实现一个markdown编辑器实例代码
May 19 #Javascript
小程序实现搜索界面 小程序实现推荐搜索列表效果
May 18 #Javascript
微信小程序实现搜索指定景点周边美食、酒店
May 18 #Javascript
You might like
全国FM电台频率大全 - 28 甘肃省
2020/03/11 无线电
PHPlet在Windows下的安装
2006/10/09 PHP
使用网络地址转换实现多服务器负载均衡
2006/10/09 PHP
php表单转换textarea换行符的方法
2010/09/10 PHP
PHP调用Linux的命令行执行文件压缩命令
2013/01/27 PHP
php查询mysql数据库并将结果保存到数组的方法
2015/03/18 PHP
thinkphp框架实现数据添加和显示功能
2016/06/29 PHP
laravel-admin的多级联动方法
2019/09/30 PHP
11款基于Javascript的文件管理器
2009/10/25 Javascript
input的focus方法使用
2010/03/13 Javascript
js实现在页面上弹出蒙板技巧简单实用
2013/04/16 Javascript
js正则表达式验证邮件地址
2015/11/12 Javascript
js自定义回调函数
2015/12/13 Javascript
Node.js的文件权限及读写flag详解
2016/10/11 Javascript
简单实现JS计算器功能
2016/12/21 Javascript
谈谈JavaScript数组常用方法总结
2017/01/24 Javascript
基于jQuery实现瀑布流页面
2017/04/11 jQuery
Vue2.0 UI框架ElementUI使用方法详解
2017/04/14 Javascript
结合Vue控制字符和字节的显示个数的示例
2018/05/17 Javascript
javascript判断一个变量是数组还是对象
2019/04/10 Javascript
[00:52]玛尔斯技能全介绍
2019/03/06 DOTA
python生成随机密码或随机字符串的方法
2015/07/03 Python
Python中文分词实现方法(安装pymmseg)
2016/06/14 Python
Centos Python2 升级到Python3的简单实现
2016/06/21 Python
python微信跳一跳系列之自动计算跳一跳距离
2018/02/26 Python
python 获取指定文件夹下所有文件名称并写入列表的实例
2018/04/23 Python
解决Django的request.POST获取不到内容的问题
2018/05/28 Python
Python pip配置国内源的方法
2020/02/14 Python
python更新数据库中某个字段的数据(方法详解)
2020/11/18 Python
CSS3 优势以及网页设计师如何使用CSS3技术
2009/07/29 HTML / CSS
Footshop罗马尼亚:最好的运动鞋选择
2019/09/10 全球购物
新闻专业本科生的自我评价分享
2013/11/20 职场文书
项目经理岗位职责范本
2015/04/01 职场文书
银行催款通知书
2015/04/17 职场文书
师范生见习总结范文
2015/06/23 职场文书
2015中秋祝酒词
2015/08/12 职场文书