微信小程式 -- 聊天室小程式(雲開發)
從微信小程式開發社群更新watch
介面之後,一直在構思這個專案。專案已經完成很久,但是一直都沒有空寫一篇部落格記錄展示一下。
開源地址
wx-cloud-im: 基於微信雲開發 cloudbase 構建聊天小程式 提供即時通訊
技術棧
雲開發 | NodeJS |
功能實現
- 即時訊息監聽推送
使用
watch
介面(見附錄),對資料庫資訊變動進行監聽,實現 訂閱-釋出 形式的訊息推送,同時在小程式端也完成了訊息推送聊天介面變化的動畫實現
- 文字內容安全核驗
使用微信小程式
openapi
對文字內容安全進行校驗
- 圖片內容安全核驗及重複性檢查
將圖片轉為
Buffer
形式上傳,並進行內容安全校驗,同時計算Buffer
的MD5
值,實現重複性檢查
- 歷史訊息查詢
通過對
scroll-view
的ID
錨點的計算,達到平滑切換資訊的效果
- 小黑屋功能:禁止使用者發言
無法通過內容安全校驗的資訊會被記錄下來,管理員可以呼叫
cloud-user-black
雲函式對對應使用者進行封禁,同時計時器自動每天觸發一次,使用者到達封禁日期期限自動解除發言限制
- 訊息位置錨定
scroll-view
新訊息和歷史訊息平滑的動畫效果
效果預覽
資料表設計
chat-users 聊天室使用者資訊表
欄位 | 說明 | 型別 |
---|---|---|
_id | 資料庫記錄唯一ID | string |
openid | 使用者唯一身份識別ID | string |
userInfo | 使用者頭像 暱稱 地址等資訊 | object |
chat-users-ban 聊天室小黑屋資訊表
欄位 | 說明 | 型別 |
---|---|---|
_id | 資料庫記錄唯一ID | string |
ban_date | 禁言時長 單位天 | number |
_createTime | 記錄建立時間 | string |
_updateTime | 記錄更新時間 | string |
chat-msgs 訊息記錄表
欄位 | 說明 | 型別 |
---|---|---|
_id | 資料庫記錄唯一ID | string |
roomId | 會話房間號 | number |
openid | 訊息傳送者openid | string |
msgType | 訊息型別 目前有 text image | string |
content | 訊息內容 text :對應訊息內容 image:對應圖片地址 | string |
userInfo | 使用者頭像 暱稱 地址等資訊 | object |
_createTime | 訊息建立時間 | string |
chat-msgs-ban 非法訊息記錄表(內容/圖片安全校驗不通過)
欄位 | 說明 | 型別 |
---|---|---|
_id | 資料庫記錄唯一ID | string |
roomId | 會話房間號 | number |
openid | 訊息傳送者openid | string |
msgType | 訊息型別 目前有 text image | string |
content | 訊息內容 text :對應訊息內容 image:對應圖片地址 | string |
userInfo | 使用者頭像 暱稱 地址等資訊 | object |
_createTime | 訊息建立時間 | string |
擴充開發
專案提供的聊天室Demo
為單聊天室模式,預設roomId = 1
。為如果想要做成多使用者聊天不同的形式,如QQ
,只需要做如下幾個步驟
-
自定義資料集合,為不同使用者之間聊天分配不同的
roomId
-
引用元件時傳入不同
roomId
即可<chat-box roomId="{{roomId}}"></chat-box>
-
呼叫訊息傳送雲函式時,傳入
roomId
TIPS
建議複用index/index.js
頁面,只需跳轉該頁面時,攜帶roomId
引數,並賦值給data
中的roomId
即可
onLoad: function (options){
this.setData({
roomId:options.roomId
})
}
附錄
watch
監聽集合中符合查詢條件的資料的更新事件。使用 watch
時,支援 where
, orderBy
, limit
,不支援 field
。
引數
屬性 | 型別 | 預設值 | 必填 | 說明 |
---|---|---|---|---|
onChange | function | 是 | 成功回撥,回撥傳入的引數 snapshot 是變更快照,snapshot 定義見下方 | |
onError | function | 是 | 失敗回撥 |
返回值
Watcher 物件
屬性 | 型別 | 說明 |
---|---|---|
close | function | 關閉監聽,無需引數,返回 Promise,會在關閉完成時 resolve |
引數說明
snapshot 說明
欄位 | 型別 | 說明 |
---|---|---|
docChanges | ChangeEvent[] | 更新事件陣列 |
docs | object[] | 資料快照,表示此更新事件發生後查詢語句對應的查詢結果 |
type | string | 快照型別,僅在第一次初始化資料時有值為 init |
id | number | 變更事件 id |
ChangeEvent 說明
欄位 | 型別 | 說明 |
---|---|---|
id | number | 更新事件 id |
queueType | string | 列表更新型別,表示更新事件對監聽列表的影響,列舉值,定義見 QueueType |
dataType | string | 資料更新型別,表示記錄的具體更新型別,列舉值,定義見 DataType |
docId | string | 更新的記錄 id |
doc | object | 更新的完整記錄 |
updatedFields | object | 所有更新的欄位及欄位更新後的值,key 為更新的欄位路徑,value 為欄位更新後的值,僅在 update 操作時有此資訊 |
removedFields | string[] | 所有被刪除的欄位,僅在 update 操作時有此資訊 |
QueueType 列舉值
列舉值 | 說明 |
---|---|
init | 初始化列表 |
update | 列表中的記錄內容有更新,但列表包含的記錄不變 |
enqueue | 記錄進入列表 |
dequeue | 記錄離開列表 |
DataType 列舉值
列舉值 | 說明 |
---|---|
init | 初始化資料 |
update | 記錄內容更新,對應 update 操作 |
replace | 記錄內容被替換,對應 set 操作 |
add | 記錄新增,對應 add 操作 |
remove | 記錄被刪除,對應 remove 操作 |
返回值說明
返回值 Watcher
上只有一個 close
方法,可以用於關閉監聽。
orderBy 與 limit
從 2.9.2
起,在監聽時支援使用 orderBy
和 limit
,如果不傳或版本號低於 2.9.2
,則預設按 id
降序排列(等同於 orderBy('id', 'desc')
),limit
預設不存在即取所有資料。
示例程式碼:根據查詢條件監聽*
const db = wx.cloud.database()
const watcher = db.collection('todos')
// 按 progress 降序
.orderBy('progress', 'desc')
// 取按 orderBy 排序之後的前 10 個
.limit(10)
// 篩選語句
.where({
// 填入當前使用者 openid,或如果使用了安全規則,則 {openid} 即代表當前使用者 openid
_openid: '{openid}'
})
// 發起監聽
.watch({
onChange: function(snapshot) {
console.log('snapshot', snapshot)
},
onError: function(err) {
console.error('the watch closed because of error', err)
}
})
示例程式碼:監聽一個記錄的變化
const db = wx.cloud.database()
const watcher = db.collection('todos').doc('x').watch({
onChange: function(snapshot) {
console.log('snapshot', snapshot)
},
onError: function(err) {
console.error('the watch closed because of error', err)
}
})
示例程式碼:關閉監聽
const db = wx.cloud.database()
const watcher = db.collection('todos').where({
_openid: 'xxx' // 填入當前使用者 openid
}).watch({
onChange: function(snapshot) {
console.log('snapshot', snapshot)
},
onError: function(err) {
console.error('the watch closed because of error', err)
}
})
// ...
// 關閉
await watcher.close()