天天看點

用node.js實作微信小程式實時聊天功能

我對IM這塊可謂是真正的小白,是以沒接觸過的可以來參考參考。

在微信這個聊天工具裡的小程式上實作聊天功能,總感覺怪怪的。但上司要求了,總是要幹的。

然後就實時通訊這個關鍵詞展開搜尋,穿梭于網頁之間。不過粘貼複制的真的太多了,找了半天也沒找到想要的,不過還是提取到了關鍵詞的WebSocket和node.js的,然後搜尋這兩是啥,什麼關系,總算明白了一點。

最後确定了第一步需要幹的是用node.js搭建服務(我是裝在自己的windows下的):

1.首先到官網下載下傳node.js,下載下傳連結

   安裝很簡單,輕按兩下下載下傳好的檔案,直接下一步一步,沒什麼特殊的選擇,路徑預設就好

   可以打開指令行視窗輸入 node -v會輸出版本,來檢驗是否安裝成功,其實這個也沒什麼必要

用node.js實作微信小程式實時聊天功能

2.然後建立一個檔案夾(我的node.js是安裝在Ç盤的,然後再d盤下建立了個叫webSocket的檔案夾)

   然後用指令轉到該目錄下:在這個檔案下安裝我們要使用的子產品:安裝子產品前需要先生成一個配置檔案,不然會報錯(反正我報了)

用node.js實作微信小程式實時聊天功能

   生成配置檔案指令:npm init -f

   執行後可以看到在該檔案下多了一個叫package.json的配置檔案,先不用管(後面也沒管過),接下來繼續安裝子產品的操作

   剛開始我是安裝的socket.io,後來發現小程式根本用不了,是以這裡也不說socket.io了。我們這裡用ws

   安裝ws指令:npm install --save ws(解除安裝子產品指令:npm uninstall  子產品名字)

3.安裝好子產品後,在你目錄下建立一個.js檔案,我這是一個ws.js

我這裡肯定會比你們的檔案要多,不用在意。

用node.js實作微信小程式實時聊天功能

然後打開這個.js檔案,開始編輯你的服務端代碼,這個随便你用記事本還是其他什麼軟體

這是最簡單基礎的一個打開連接配接,響應的代碼:

//引入ws子產品
const WebSocket = require('ws');
//建立服務 port是端口
const wss = new WebSocket.Server({ port: 80});
//用戶端連接配接時會進這個
wss.on('connection', function connection(ws) {
    console.log('連接配接成功');
    //用戶端發送消息時會觸發這個
    ws.on('message', function incoming(data) {
        console.log('收到消息');
        //data是用戶端發送的消息,這裡clients.foreach是廣播給所有用戶端
        wss.clients.forEach(function each(client) {
            //把用戶端發來的data,循環發給每個用戶端
            client.send(data);
        });
    });
});
           

這裡貼上稍微比較完善的代碼,這裡是用資料庫儲存的發送的消息,用的mysql,是以需要在安裝mysql子產品

npm install --save mysql

代碼:

這裡有很多注釋的代碼,都是我鼓搗時用到的,可以無視或删掉

這個MySQL的資料連接配接需要根據自己的修改,表也是

我這用到的表就兩個字段 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');
//驗證函數
function ClientVerify(info) {
    var ret = false;//拒絕
    //url參數
    var params = url.parse(info.req.url, true).query;
    //console.log(groupid);
    //groupid=params['groupid']
    //誰誰誰來到了讨論組
    // wss.clients.forEach(function each(client) {
    //     client.send('233');
    // });
    return true;

}
var wss = new ws.Server( { server: server,verifyClient: ClientVerify } );

/*//引入資料庫
 var mysql = require('mysql');
 //連接配接資料庫資訊 普通版
 var connection = mysql.createConnection({
    host  : '1.1.1.1',//資料庫連結
    user  : 'root',
    password : 'root',
    database : 'bootdo'
});*/
//引入資料庫
var mysql = require('mysql');
// 建立資料池
const pool  = mysql.createPool({
    host     : '1.1.1.1',   // 資料庫位址
    user     : 'root',    // 資料庫使用者
    password : 'root',   // 資料庫密碼
    database : 'bootdo'  // 選中資料庫
})
/*接收一個sql語句 以及所需的values
這裡接收第二參數values的原因是可以使用mysql的占位符 '?'
比如 query(`select * from my_database where id = ?`, [1])
好像可以直接使用pool.query,暫時不明*/
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();
                //事件驅動回調
                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語句',sql);
    query(sql,function (err,res,fields) {
        console.log('sql操作傳回:', res);
        if(res!=null){
            ws.send(JSON.stringify(res));
        }
    });
    //監聽用戶端發送得消息
    ws.on('message', function incoming(data) {
        console.log('來自用戶端得message:',data);
        //儲存用戶端發送得消息到資料庫
        sql="insert into hi_test(msg) values(?)";
        console.log('sql語句',sql);
        query(sql,data,function (err,res,fields) {
            console.log('sql操作傳回:',res);//res.insertId
        });
        var sendData=JSON.stringify([{msg:data}])
        /**
         * 把消息發送到所有的用戶端
         * wss.clients擷取所有連結的用戶端
         */
        wss.clients.forEach(function each(client) {
            client.send(sendData);
        });
    });
});

server.listen(80, function listening() {
    console.log('伺服器啟動成功!');
});



/*發起get請求
var options = {
    hostname: 'www.tjjxsoft.cn',
    path: '/attendanceParameter/getAttendanceParameter/13',
    method: 'GET'
};

var req = http.request(options, function (res) {
    console.log('狀态: ' + res.statusCode);
    res.on('data', function (chunk) {
        console.log('傳回資料: ' + chunk);
    });
});

req.on('error', function (e) {
    console.log('problem with request: ' + e.message);
});

req.end();*/

/*
/!*建構http服務*!/
var app = require('http').createServer()
/!*引入socket.io*!/
var io = require('socket.io')(app);
/!*定義監聽端口,可以自定義,端口不要被占用*!/
var PORT = 80;
/!*監聽端口*!/
app.listen(PORT);

/!*定義使用者數組*!/
var users = [];
/!**
 *監聽用戶端連接配接
 *io是我們定義的服務端的socket
 *回調函數裡面的socket是本次連接配接的用戶端socket
 *io與socket是一對多的關系
 *!/
io.on('connection', function (socket) {
    /!*所有的監聽on,與發送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(你自己的檔案名)回車,就已經啟動了服務

用node.js實作微信小程式實時聊天功能

4.現在服務就已經起來了,接下來弄小程式這邊的

直接貼代碼:

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>
                        <!-- 我這用的是自己另一個服務的圖檔 -->
                            <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>
                        <!-- 我這用的是自己另一個服務的圖檔 -->
                            <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="輸入聊天内容" value='{{sendText}}' />
        <button bindtap='sendBtn' type="primary">發送</button>
    </view>
</view>
           

js:

var app = getApp();
Page({
    data: {
        socket_open: false,//判斷連接配接是否打開
        sendText: "",//發送的消息
        serverMsg: [],//接受的服務端的消息
        userInfo: { userId: 1, name: "呵呵",img:'頭像'},//app.appData.userInfo,
        scrolltop: 999
    },

    /**輸入内容 */
    sendTextBind: function(e) {
        this.setData({
            sendText: e.detail.value
        });
        console.log(this.data.sendText);
    },
    /**發送消息 */
    sendBtn: function(e) {
        console.log('發送消息事件!');
        var msgJson = {
            user: {
                id: this.data.userInfo.userId,//app.appData.userInfo.userId, //唯一ID區分身份
                name: this.data.userInfo.name, //顯示用姓名
                img: this.data.userInfo.img, //顯示用頭像
            },
            msg: this.data.sendText,//發送的消息
            groupid:1
        }
        //發送消息
        this.send_socket_message(JSON.stringify(msgJson));
        this.setData({
            sendText: ""//發送消息後,清空文本框
        });
    },
    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
        })
        //監聽WebSocket連接配接打開事件。
        wx.onSocketOpen(function(res) {
            console.log('WebSocket連接配接已打開!');
            that.setData({
                socket_open: true
            });
        });
        //監聽WebSocket接受到伺服器的消息事件。
        wx.onSocketMessage(function(res) {
            console.log('收到伺服器内容:', 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);
            }
        });
        //監聽WebSocket錯誤。
        wx.onSocketError(function(res) {
            console.log('WebSocket連接配接打開失敗,請檢查!', res)
        });

    },
    send_socket_message: function(msg) {
        //socket_open,連接配接打開的回調後才會為true,然後才能發送消息
        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;
}
           

效果圖:

用node.js實作微信小程式實時聊天功能

預覽的時候一定要打開調試,因為這不是WSS協定,是沒法直接用的

繼續閱讀