天天看點

微信小程式開發聊天室——實時聊天,支援圖檔預覽

第一次寫小程式,老闆就讓我用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}}" 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}}" 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);

}

}
           

背景代碼(圖檔):

微信小程式開發聊天室——實時聊天,支援圖檔預覽