使用node.js實(shí)現(xiàn)微信小程序?qū)崟r(shí)聊天功能
在微信這個(gè)聊天工具里的小程序上實(shí)現(xiàn)聊天功能,總感覺怪怪的。但領(lǐng)導(dǎo)要求了,總是要干的。
然后就實(shí)時(shí)通訊這個(gè)關(guān)鍵詞展開搜索,穿梭于網(wǎng)頁(yè)之間。不過粘貼復(fù)制的真的太多了,找了半天也沒找到想要的,不過還是提取到了關(guān)鍵詞的WebSocket和node.js的,然后搜索這兩是啥,什么關(guān)系,總算明白了一點(diǎn)。
最后確定了第一步需要干的是用node.js搭建服務(wù)(我是裝在自己的windows下的):
1.首先到官網(wǎng)下載node.js,下載鏈接
安裝很簡(jiǎn)單,雙擊下載好的文件,直接下一步一步,沒什么特殊的選擇,路徑默認(rèn)就好
可以打開命令行窗口輸入 node -v會(huì)輸出版本,來檢驗(yàn)是否安裝成功,其實(shí)這個(gè)也沒什么必要

2.然后新建一個(gè)文件夾(我的node.js是安裝在Ç盤的,然后再d盤下新建了個(gè)叫webSocket的文件夾)
然后用命令轉(zhuǎn)到該目錄下:在這個(gè)文件下安裝我們要使用的模塊:安裝模塊前需要先生成一個(gè)配置文件,不然會(huì)報(bào)錯(cuò)(反正我報(bào)了)

生成配置文件命令:npm init -f
執(zhí)行后可以看到在該文件下多了一個(gè)叫package.json的配置文件,先不用管(后面也沒管過),接下來繼續(xù)安裝模塊的操作
剛開始我是安裝的socket.io,后來發(fā)現(xiàn)小程序根本用不了,所以這里也不說socket.io了。我們這里用ws
安裝ws命令:npm install --save ws(卸載模塊命令:npm uninstall 模塊名字)
3.安裝好模塊后,在你目錄下創(chuàng)建一個(gè).js文件,我這是一個(gè)ws.js
我這里肯定會(huì)比你們的文件要多,不用在意。

然后打開這個(gè).js文件,開始編輯你的服務(wù)端代碼,這個(gè)隨便你用記事本還是其他什么軟件
這是最簡(jiǎn)單基礎(chǔ)的一個(gè)打開連接,響應(yīng)的代碼:
//引入ws模塊
const WebSocket = require('ws');
//創(chuàng)建服務(wù) port是端口
const wss = new WebSocket.Server({ port: 80});
//客戶端連接時(shí)會(huì)進(jìn)這個(gè)
wss.on('connection', function connection(ws) {
console.log('連接成功');
//客戶端發(fā)送消息時(shí)會(huì)觸發(fā)這個(gè)
ws.on('message', function incoming(data) {
console.log('收到消息');
//data是客戶端發(fā)送的消息,這里clients.foreach是廣播給所有客戶端
wss.clients.forEach(function each(client) {
//把客戶端發(fā)來的data,循環(huán)發(fā)給每個(gè)客戶端
client.send(data);
});
});
});
這里貼上稍微比較完善的代碼,這里是用數(shù)據(jù)庫(kù)保存的發(fā)送的消息,用的mysql,所以需要在安裝mysql模塊
npm install --save mysql
代碼:
這里有很多注釋的代碼,都是我鼓搗時(shí)用到的,可以無視或刪掉
這個(gè)MySQL的數(shù)據(jù)連接需要根據(jù)自己的修改,表也是
我這用到的表就兩個(gè)字段 id ,msg
var http=require('http');
var qs = require('querystring'); //
var ws=require('ws');
var server=http.createServer(function (req, res) {
res.end("This is a WebSockets server!");
});
var url = require('url');
//驗(yàn)證函數(shù)
function ClientVerify(info) {
var ret = false;//拒絕
//url參數(shù)
var params = url.parse(info.req.url, true).query;
//console.log(groupid);
//groupid=params['groupid']
//誰(shuí)誰(shuí)誰(shuí)來到了討論組
// wss.clients.forEach(function each(client) {
// client.send('233');
// });
return true;
}
var wss = new ws.Server( { server: server,verifyClient: ClientVerify } );
/*//引入數(shù)據(jù)庫(kù)
var mysql = require('mysql');
//連接數(shù)據(jù)庫(kù)信息 普通版
var connection = mysql.createConnection({
host : '58.87.94.16',
user : 'root',
password : 'root',
database : 'bootdo'
});*/
//引入數(shù)據(jù)庫(kù)
var mysql = require('mysql');
// 創(chuàng)建數(shù)據(jù)池
const pool = mysql.createPool({
host : '58.87.94.16', // 數(shù)據(jù)庫(kù)地址
user : 'root', // 數(shù)據(jù)庫(kù)用戶
password : 'root', // 數(shù)據(jù)庫(kù)密碼
database : 'bootdo' // 選中數(shù)據(jù)庫(kù)
})
/*接收一個(gè)sql語(yǔ)句 以及所需的values
這里接收第二參數(shù)values的原因是可以使用mysql的占位符 '?'
比如 query(`select * from my_database where id = ?`, [1])
好像可以直接使用pool.query,暫時(shí)不明*/
let query = function(sql,values,callback){
pool.getConnection(function(err,conn){
if(err){
callback(err,null,null);
}else{
conn.query(sql,values,function(err,results,fields){
//釋放連接
conn.release();
//事件驅(qū)動(dòng)回調(diào)
callback(err,results,fields);
});
}
});
};
module.exports=query;
wss.on('connection', function connection(ws) {
console.log('鏈接成功!');
//console.log(ws);
//查詢歷史聊天記錄 廣播給連接的客戶端
var sql='select * from hi_test where groupid=1';
console.log('sql語(yǔ)句',sql);
query(sql,function (err,res,fields) {
console.log('sql操作返回:', res);
if(res!=null){
ws.send(JSON.stringify(res));
}
});
//監(jiān)聽客戶端發(fā)送得消息
ws.on('message', function incoming(data) {
console.log('來自客戶端得message:',data);
//保存客戶端發(fā)送得消息到數(shù)據(jù)庫(kù)
sql="insert into hi_test(msg) values(?)";
console.log('sql語(yǔ)句',sql);
query(sql,data,function (err,res,fields) {
console.log('sql操作返回:',res);//res.insertId
});
var sendData=JSON.stringify([{msg:data}])
/**
* 把消息發(fā)送到所有的客戶端
* wss.clients獲取所有鏈接的客戶端
*/
wss.clients.forEach(function each(client) {
client.send(sendData);
});
});
});
server.listen(80, function listening() {
console.log('服務(wù)器啟動(dòng)成功!');
});
/*發(fā)起get請(qǐng)求
var options = {
hostname: 'www.tjjxsoft.cn',
path: '/attendanceParameter/getAttendanceParameter/13',
method: 'GET'
};
var req = http.request(options, function (res) {
console.log('狀態(tài): ' + res.statusCode);
res.on('data', function (chunk) {
console.log('返回?cái)?shù)據(jù): ' + chunk);
});
});
req.on('error', function (e) {
console.log('problem with request: ' + e.message);
});
req.end();*/
/*
/!*構(gòu)建http服務(wù)*!/
var app = require('http').createServer()
/!*引入socket.io*!/
var io = require('socket.io')(app);
/!*定義監(jiān)聽端口,可以自定義,端口不要被占用*!/
var PORT = 80;
/!*監(jiān)聽端口*!/
app.listen(PORT);
/!*定義用戶數(shù)組*!/
var users = [];
/!**
*監(jiān)聽客戶端連接
*io是我們定義的服務(wù)端的socket
*回調(diào)函數(shù)里面的socket是本次連接的客戶端socket
*io與socket是一對(duì)多的關(guān)系
*!/
io.on('connection', function (socket) {
/!*所有的監(jiān)聽on,與發(fā)送emit都得寫在連接里面,包括斷開連接*!/
socket.on('login',function(data){
console.log('有人登錄了:')
console.log(data);
users.push({
username:data.username
});
/!*向所有連接的客戶端廣播add事件*!/
io.sockets.emit('add',data)
})
})
console.log('app listen at'+PORT);*/
然后命令行輸入node ws.js(你自己的文件名)回車,就已經(jīng)啟動(dòng)了服務(wù)

4.現(xiàn)在服務(wù)就已經(jīng)起來了,接下來弄小程序這邊的
直接貼代碼:
wxml:
<view class='homeView'>
<scroll-view scroll-y style="height:500px;" scroll-top='{{scrolltop}}'>
<view class='listView'>
<block wx:for="{{serverMsg}}" wx:key='*this'>
<!-- -->
<view wx:if="{{item.user.id!=userInfo.userId}}" class='leftView'>
<view class='name'>{{item.user.name}}</view>
<view class='imgmsgleft'>
<view>
<!-- 我這用的是自己另一個(gè)服務(wù)的圖片 -->
<image class='touimg' src='https://www.tjjxsoft.cn/static/images/img005.png'></image>
</view>
<view>{{item.msg}}</view>
</view>
</view>
<view wx:else class='rightView'>
<view class='name'>{{item.user.name}}</view>
<view class='imgmsg'>
<view>{{item.msg}}</view>
<view>
<!-- 我這用的是自己另一個(gè)服務(wù)的圖片 -->
<image class='touimg' src='https://www.tjjxsoft.cn/static/images/img005.png'></image>
</view>
</view>
</view>
</block>
</view>
</scroll-view>
<view class='sendView'>
<input bindinput='sendTextBind' placeholder="輸入聊天內(nèi)容" value='{{sendText}}' />
<button bindtap='sendBtn' type="primary">發(fā)送</button>
</view>
</view>
js:
var app = getApp();
Page({
data: {
socket_open: false,//判斷連接是否打開
sendText: "",//發(fā)送的消息
serverMsg: [],//接受的服務(wù)端的消息
userInfo: { userId: 1, name: "呵呵",img:'頭像'},//app.appData.userInfo,
scrolltop: 999
},
/**輸入內(nèi)容 */
sendTextBind: function(e) {
this.setData({
sendText: e.detail.value
});
console.log(this.data.sendText);
},
/**發(fā)送消息 */
sendBtn: function(e) {
console.log('發(fā)送消息事件!');
var msgJson = {
user: {
id: this.data.userInfo.userId,//app.appData.userInfo.userId, //唯一ID區(qū)分身份
name: this.data.userInfo.name, //顯示用姓名
img: this.data.userInfo.img, //顯示用頭像
},
msg: this.data.sendText,//發(fā)送的消息
groupid:1
}
//發(fā)送消息
this.send_socket_message(JSON.stringify(msgJson));
this.setData({
sendText: ""http://發(fā)送消息后,清空文本框
});
},
onLoad: function(options) {
// app.login();
// this.setData({
// userInfo: app.appData.userInfo
// });
//初始化
this.wssInit();
},
wssInit() {
var that = this;
//建立連接
wx.connectSocket({
url: 'ws://localhost'//app.appData.socket
})
//監(jiān)聽WebSocket連接打開事件。
wx.onSocketOpen(function(res) {
console.log('WebSocket連接已打開!');
that.setData({
socket_open: true
});
});
//監(jiān)聽WebSocket接受到服務(wù)器的消息事件。
wx.onSocketMessage(function(res) {
console.log('收到服務(wù)器內(nèi)容:', res);
var server_msg = JSON.parse(res.data);
console.log(server_msg);
if (server_msg != null) {
var msgnew = [];
for (var i = 0; i < server_msg.length; i++) {
msgnew.push(JSON.parse(server_msg[i].msg));
}
msgnew=that.data.serverMsg.concat(msgnew);
that.setData({
serverMsg: msgnew,
scrolltop: msgnew.length * 100
});
console.log(that.data.serverMsg);
}
});
//監(jiān)聽WebSocket錯(cuò)誤。
wx.onSocketError(function(res) {
console.log('WebSocket連接打開失敗,請(qǐng)檢查!', res)
});
},
send_socket_message: function(msg) {
//socket_open,連接打開的回調(diào)后才會(huì)為true,然后才能發(fā)送消息
if (this.data.socket_open) {
wx.sendSocketMessage({
data: msg
})
}
}
})
wxss:
.homeView {
border-top: 1px solid #ededed;
}
.listView{
padding-bottom: 50px;
}
.listView>view {
padding: 10px;
}
.rightView {
text-align: right;
}
.imgmsgleft {
display: flex;
justify-content: flex-start;
align-items: center;
}
.imgmsgleft>view:last-child {
border: solid 1px gray;
padding: 10px;
border-radius: 6px;
}
.imgmsg {
display: flex;
justify-content: flex-end;
align-items: center;
}
.imgmsg>view:first-child {
border: solid 1px gray;
padding: 10px;
border-radius: 6px;
background-color: green;
}
.touimg {
width: 50px;
height: 50px;
}
.name {
font-size: 14px;
color: gray;
}
.sendView {
display: flex;
width: 100%;
position: fixed;
bottom: 0px;
border-top: 1px #ededed solid;
background-color: white;
}
.sendView>button {
width: 20%;
}
.sendView>input {
width: 80%;
height: auto;
}
效果圖:

預(yù)覽的時(shí)候一定要打開調(diào)試,因?yàn)檫@不是WSS協(xié)議,是沒法直接用的、
總結(jié)
以上所述是小編給大家介紹的使用node.js實(shí)現(xiàn)微信小程序?qū)崟r(shí)聊天功能,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
nest.js,egg.js,midway,express,koa的區(qū)別小結(jié)
本文主要介紹了nest.js,egg.js,midway,express,koa的區(qū)別小結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
node連接kafka2.0實(shí)現(xiàn)方法示例
這篇文章主要介紹了node連接kafka2.0,nodejs連接kafka2.0的實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了kafka2.0的功能、原理、以及node.js連接kafka2.0的具體實(shí)現(xiàn)技巧,需要的朋友可以參考下2023-05-05
Nodejs實(shí)現(xiàn)獲取實(shí)時(shí)數(shù)據(jù)的三種主流方式詳解
這篇文章主要為大家詳細(xì)介紹了Nodejs前端獲取實(shí)時(shí)數(shù)據(jù)的三種主流方式,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02
詳解nodejs微信公眾號(hào)開發(fā)——2.自動(dòng)回復(fù)
這篇文章主要介紹了詳解nodejs微信公眾號(hào)開發(fā)——2.自動(dòng)回復(fù),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-04-04
nodejs 實(shí)現(xiàn)模擬form表單上傳文件
使用nodejs來模擬form表單進(jìn)行文件上傳,可以同時(shí)上傳多個(gè)文件。2014-07-07
node.js將MongoDB數(shù)據(jù)同步到MySQL的步驟
這篇文章主要給大家介紹了關(guān)于node.js將MongoDB數(shù)據(jù)同步到MySQL的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12

