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

第一次写小程序,老板就让我用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);

}

}

后台代码(图片):

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

(0)

相关推荐

  • 微信小程序 聊天室简单实现

    微信小程序 聊天室简单实现 utils文件夹下websoctet.js文件 var url = 'ws://地址端口'; function connect(user, func) { wx.connectSocket({ url: url, header: {"content-type":'application/x-www-form-urlencoded'} }); wx.onSocketOpen(function (res) { send('{"type":&q

  • 微信小程序实现图片预览功能

    本文为大家分享了微信小程序实现图片预览的具体代码,供大家参考,具体内容如下 效果图 原理 使用wx.chooseImage选择本地图片: 使用wx.previewImage预览图片. WXML <view> <button bindtap="previewImage" type="primary">图片上传预览</button> <view class="tui-content"> <imag

  • 微信小程序websocket聊天室的实现示例代码

    背景 最近做了一个微信小程序的即时通讯功能,之前我也做过node.js的websocket服务,不过是在web端应用的socket.io服务.小程序本身对http.websocket等连接均有诸多限制,所以这次项目选择了node.js自带的ws模块. 服务端 初始化一个node.js项目,引入ws模块 const webSocket = require('ws'); 创建websocket实例,并设置监听端口 const wss = new webSocket.Server({ port: 30

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

    第一次写小程序,老板就让我用websoket写个聊天对话,群聊这种.第一次写聊天功能,第一次用websoket,第一次用小程序,这是在考验我吗?不过我还是研究了一下,终于实现了. 首先看一下界面,界面很简单,就是首页刚进来获取了用户信息头像,昵称等.点击进入聊天室就可以聊天了,下面我介绍的是前端代码实现,后台需要做的很简单,就是你给他发送什么数据,他就给你返回什么数据,就是在接收前台发送过来的图片的时候需要做个格式转换,因为有时候前端将接收到的json字符串转换json对象的时候,遇到有特殊的标

  • 详解微信小程序开发用户授权登陆

    本篇将帮助读者实现基于 微信开发者工具 & C#环境 下的用户在小程序上的授权登陆. 准备: 微信开发者工具下载地址:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html 微信小程序开发文档:https://developers.weixin.qq.com/miniprogram/dev/index.html 开发: 在开发之初,我们需要先明确微信方已经制定好的授权登陆流程,参看 官方API - 登陆接口.

  • 详解微信小程序开发(项目从零开始)

    一.序 微信小程序,估计大家都不陌生,现在应用场景特别多.今天就系统的介绍一下小程序开发.注意,这里只从项目代码上做解析,不涉及小程序如何申请.打包.发布的东西.(这些跟着微信官方文档的流程走就好).好了废话不多说,看目录. 注: 小程序是一套特殊的东西,融合了原生和web端.他是一个不完整的浏览器对象,所以很多DOM . BOM 的东西无法使用,但是他又通过微信APP实现了多线程. 二.如何创建小程序 很简单,首先下载微信开发者工具,下载稳定版本的就好. 下载 然后,创建小程序,可以参考下述图

  • 详解微信小程序开发—你期待的分享功能来了,微信小程序序新增5大功能

    微信小程序在12月21日发布了新版本的开发工具,并在官网公布新增分享.模板消息.客服消息.扫一扫.带参数二维码功能. 有了分享功能,相信会给很多创业者带来了无限的可能性! 下面就来看看这些新功能到底怎么用吧! 1.分享 可以分享小程序的任何一个页面给好友或群聊.注意是分享给好友或群聊,并没有分享到朋友圈.一方面微信在尝试流量分发方式,但同时又不愿意开放最大的流量入口. 开发文档:https://mp.weixin.qq.com/debug/wxadoc/dev/api/share.html?t=

  • 详解微信小程序开发之下拉刷新 上拉加载

    微信小程序中的下拉刷新,上拉加载的功能很常见,目前我知道的有两种可行的方法,一是scroll-view,二是整个页面刷新.今天说说第一种,自己造轮子,难免有些瑕疵,日后慢慢完善. 上gif: 原理: scroll-view中有监听滑动的方法,这个跟Android类似.其中用到了滑动到顶部,滑动到底部的方法. 1.下拉刷新,在滑动到顶部时,bindscrolltoupper被调用,根据自己的业务逻辑请求即可.我的demo只是随机换了个关键字. 2.上拉加载,在滑动到底部时,bindscrollto

  • 详解微信小程序开发之城市选择器 城市切换

    移动开发中城市选择器必不可少. 空白造了个. gif: 这里只上部分js代码: var city = require('../../utils/city.js'); Page({ data: { searchLetter: [], showLetter: "", winHeight: 0, tHeight: 0, bHeight: 0, startPageY: 0, cityList: [], isShowLetter: false, scrollTop: 0, city: "

  • 详解微信小程序开发之——wx.showToast(OBJECT)的使用

    wx.showToast API是显示消息提示框的作用. 先让我们看一下官方的文档说明: 注意:其中的图标,只支持"success"."loading" 示例代码: wx.showToast({ title: '成功', icon: 'success', duration: 2000 }) 接下来演示如何使用,先打开微信web开发者工具,新建快速项目,删除掉首页没用的内容,保留如下部分. 添加两个按钮,同事添加点击事件.再在按钮上添加navigator导航,链接到默

  • 详解微信小程序 登录获取unionid

    详解微信小程序 登录获取unionid 首先公司开发了小程序, 公众号网页和app等, 之前都是用的openid来区分用户, 但openid只能标识用户在当前小程序或公众号里唯一, 我们希望用户可以在公司各个产品(比如公众号, 小程序, app里的微信登录)之间, 可以保持用户的唯一性, 还好微信给出了unionid. 下面分两步介绍一下 微信小程序 获取unionid的过程. 1. 首先 在微信公众平台注册小程序 , 然后在小程序上模拟登录流程. 注 : 这里只是简单登录流程, 实际中需要维护

  • 详解微信小程序中的页面代码中的模板的封装

    详解微信小程序中的页面代码中的模板的封装 最近在进行微信小程序中的页面开发,其实在c++或者说是js中都会出现这种情况,就是相同的代码会反复出现,这就是进行一定的封装,封装的好处就是可以是程序中在于减少一定的代码量,并且可是使代码结构更加清晰.那今天所要记录的就是关于微信小程序中的页面的模板封装. 在微信小程序中的文件名都带有wxml等样式,在wxml中提供了模板,即可以在模板中定义代码片段,然后可以在页面中的不同位置进行调用,模板的定义: <templatename="products&

  • 详解微信小程序审核不通过的解决方法

    前言 近来,微信小程序一直活跃在开发者的眼球中.很多开发者都投身微信小程序的开发中,而这些开发者,总是需要面对最后一道难题:如何以一种优雅的姿势来通过微信官方的审核.本文基于几天前提交审核的一次总结,写得有不当的地方,请各位大佬指正. 问题描述 先上一下微信小程序平台常见拒绝情形的说明文件.由于我提交的小程序中包含了"分享群"的按钮,所以审核未通过,未通过的原因如下: 3.2.1 小程序的页面内容中,存在诱导类行为,包括但不限于诱导分享.诱导添加.诱导关注公众号.诱导下载等,要求用户分

随机推荐