第一次写小程序,老板就让我用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.jsconst 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 = thisif (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.newslistlist.push(JSON.parse(res.data))that.setData({newslist: list})})},// 页面卸载onUnload(){wx.closeSocket();wx.showToast({title: '连接已断开~',icon: "none",duration: 2000})},//事件处理函数send: function () {var flag = thisif (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 = thiswx.chooseImage({count: 1, // 默认9sizeType: ['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.srcvar 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);}}

后台代码(图片):

微信小程序开发聊天室——实时聊天,支持图片预览相关推荐

  1. 微信小程序开发—项目实战之聊天机器人

    项目功能介绍 人工智能虚拟机器人"微软小冰"大家玩过吧,很酷的一个应用.发送文字.语音和图片都能得到智能的回复. 那现在我们就用小程序做一个模拟的应用,智能聊天机器人.发送文字它可 ...

  2. 微信小程序|开发实战篇之九-image-picker图片选择器组件及其子组件

    开发实战篇之九 前言 1.grid格子组件 1.1 grid骨架文件wxml 1.2 grid的js文件分析 1.3 grid-item的wxml文件分析 1.4 grid-item的wxss文件分析 ...

  3. 微信小程序开发之使用Canas制作圆角图片

    drawImageToCanvas() {const query = wx.createSelectorQuery();query.select("#canvas").fields ...

  4. 微信小程序图片上传到服务器再自动替换,微信小程序批量上传图片到服务器,并实现预览,删除功能...

    js代码 Page({ /** 页面的初始数据 / data: { files: [], //门店图片信息,数组图片保存作为数据源 }, /* 多图片上传 */ chooseImage: functi ...

  5. 微信小程序开发导航:精品教程+网友观点+demo源码(5月9日更新)

    1:官方工具:https://mp.weixin.qq.com/debug/w ... tml?t=1476434678461 2:简易教程:https://mp.weixin.qq.com/debu ...

  6. 2019高校微信小程序开发大赛获奖作品——《brain头脑智序》

    目录 前言 交互流程说明图 我的任务 登录授权(login) 首页(tababr分析) 房间准备区(preparing) 便签编辑区 最终方案选择(房主权限) 会议报告页面(report) 前言 今年 ...

  7. 微信小程序开发分析总结

    本文主要记录一下初次开发小程序一些注意事项,小程序开发语言,对小程序的审核要求,小程序的特点,开发特点,后面会再写下是否有三方好用的工具,及开发中遇到的js,html,css 相关的问题及解决方法.毕 ...

  8. 七天学习微信小程序开发(一)—— 学习笔记

    文章目录 前言 目标 第一天 -- 前端配置和编写 微信开发 微信小程序的代码结构 常用标签(wxml) 常用样式(wxss) 界面布局的技术 任务 第二天 -- 深度学习微信前端编写(一) 程序底部 ...

  9. 微信小程序开发系列——注册申请

    摘要:本文介绍微信小程序开发前需要登录微信公众号平台的的邮箱申请 1.前言背景 上周参加了个老乡聚会,吃饭聊天时接触到老乡在创业时有需要做微信.支付宝的小程序,作为聚餐中唯一一个上班族的程序猿,于是问 ...

  10. 微信小程序开发个人笔记(2)

    微信小程序开发基础笔记 官方文档:微信官方文档 | 微信开放文档 (qq.com) 一.注册等 首先需要注册一下平台(Appid开发者d 和上传管理等都需要) 微信公众平台 (qq.com)(找不到就 ...

最新文章

  1. echo 和 var_dump
  2. 计算机系学生thinkbook,ThinkBook系列性能差,只能当一台学习机?其实它只是专注于办公...
  3. OpenCV计算机视觉实战(Python版)资源
  4. python编程的基本方法有哪些_Python编程中常用的基础知识有哪些?
  5. Android WebView常见问题及解决方案汇总【很全很实用】
  6. 电子增稳云台_揭秘Dobby自拍无人机,电子增稳是黑科技?
  7. Java常用设计模式————单例模式
  8. 一行代码添加P值的可视化技巧分享~~
  9. 【转载】程序员历史之一
  10. 称特价影票被取消后影片仍正常放映 购票人起诉淘票票索赔500元
  11. javascript 执行效率 java_有效提高JavaScript执行效率的几点知识
  12. mupdf嵌入 html页面,MuPDF Command Line Tools
  13. 2021-07-08郝斌C语言笔记
  14. 联想电脑BIOS失败教程
  15. 2个抖音工程师搞出新工具,意外风靡字节内部,项目经理用上安静多了,程序员不骗程序员...
  16. Python学习笔记--解析式
  17. 光伏发电量和用电量的概率预测研究综述(1)
  18. 蔡氏电路matlab仿真实代码验,基于蔡氏电路的MATLAB仿真
  19. 如何获取MySQL中表的最后更新时间
  20. matlab 高精度无理数,如何从MatLab上的无理数产生近似分数?

热门文章

  1. Linux 开发环境工具 下载网址大全 --转
  2. java常见面试题答案
  3. 让swfobject.js 支持透明的flash
  4. CSS的世界(十四)
  5. Trinity(3)
  6. Python 程序示例 - 初学者的简单代码示例
  7. 软件开发项目规划时,SA、SD与SE的区别与重要性
  8. FLD5302升压8.4V充电IC芯片和FLD5303升压12.6V充电IC芯片规格书datasheet
  9. 在线接口Mock工具fastmock详解
  10. java Lambda表达式练习