1、首先要在 添加好友 這個按鈕上添加一個事件,也就是在detail.wxml的添加好友這個按鈕的哪里,添加一個點擊事件 handleAddFriend
並且添加好友還要考慮,現在是已登陸狀態還是未登陸狀態的,只有是登陸狀態的時候,才可以發起添加好友的請求的
所以就要先判斷一下它是否已經登陸了
因為只要是登陸之后,就會把用戶的id寫入到全局的userinfo下面的
handleAddFriend(){ if( app.userInfo._id){ } else{ wx.showToast({ title: '請先登陸', duration : 2000, // 然后不要讓它顯示圖標 icon : 'none', success: ()=>{ // 如果成功的話就直接跳轉到我的頁面去 // 但是注意了這里不能用 navigator to,因為它主要是跳轉 // 普通的頁面,而這里“我的頁面”其實是同tabbar來進行配置的 } }) } }
這個時候就可以查找一下 小程序文檔 中關於“路由”的介紹了
可以看到要用wx.switchtab來進行操作了
然后因為我們設置了那個提示“請先登陸”是維持兩秒鍾,所以我們也要設置這個跳轉到我的頁面中的時間也是兩秒鍾
handleAddFriend(){ if( app.userInfo._id){ } else{ wx.showToast({ title: '請先登陸', duration : 2000, // 然后不要讓它顯示圖標 icon : 'none', success: ()=>{ // 如果成功的話就直接跳轉到我的頁面去 // 但是注意了這里不能用 navigator to,因為它主要是跳轉 // 普通的頁面,而這里“我的頁面”其實是同tabbar來進行配置的 setTimeout(()=>{ wx.switchTab({ url: '/pages/user/user', }) } , 2000); } }) } }
上面的加入 沒登陸的情況也寫好了,下面就是對已經登陸了之后的設計了
就要在數據可以中建立一個message集合,主要是用來存儲好友消息,或者是系統的消息給這個用戶的一個信息集合的
這個集合里面的每一個信息,包含了userID也就是這個好友請求或者是信息是發送給哪一個人的
然后還有一個其他想要加他好友的用戶id list數組,因為每個人都可以給這個人發起好友請求的,這就是對於數據庫1的建立了
所以在已經登陸之后,先查看一下有沒有這個發起好友的信息了,如果還有的話,就在數據庫中創立這個字段了
這個數據庫里面的userid字段存的其實就是我們要加的這個人的id標識了,然后這個人的id我們可以從這個人的詳情頁面(detail)下的data中來獲得的
通過where就可以定位到在數據庫中這個用戶對應的字段了,然后用get就可以開始對這個字段里面的東西進行查詢了
如果這個信息已經存在了就做更新操作,如果不存在的話就做創建操作即可了
if( app.userInfo._id){ db.collection('mesasge').where({ userId : this.data.detail._id }).get().then((res)=>{ if( res.data.length){//更新 } else{ //tianjia1 db.collection('message').add({ data : { userId : this.data.detail._id, list : [ app.userInfo._id] } }) } }); }
之后就可以查看數據可以中的message 集合
這樣的話,說明就調用成功了
二、更新message 信息
因為如果已經申請過了的話,就不能再往list里面添加自己的id了,所以就要檢測一下現在是否在list中,
可以直接調用數組的include方法來進行查詢,如果找到了的話,就提示“已申請過了”如果沒找到的話就要往這個數組里面進行數據更新了
查看了微信開放文檔之后會發現,如果是單個數據進行更新的話可以直接用doc好到之后進行更新就好了,但是如果對大量的數據進行批量的更新的話
因為在客戶端的更新能力還是有限的,所以就要到服務端上來完成了,也就是用雲函數來完成了(其實這個方法我們已經寫好了,也就是雲函數update了
else{ wx.cloud.callFunction({ // name也就是我們要修改的數據庫的名字,data就是在雲函數中 // 想要的參數了 name : 'updata', data : { collection : 'message', where :{ userId : this.data.detail._id }, data : { } } }) }
注意了,在調用雲函數的時候,前面的data和后面的data是不一樣的,錢買你的是給雲函數的參數,但是后面的是我們要修改的數據了
在要修改list的數據到時候,就涉及了要對數組進行添加,也就是push操作了,其實在數據可以中也內置了一些的方法,commend.push等等
注意:在detail.js文件中,如果找到了這個數據流,但是沒有申請的話,就是進行更新,在更新的時候用到了update雲更新函數,
給這個雲函數傳入的data中
data : `{list : _.unshift(' ${app.userInfo._id} ')}`
注意:最外面那層 並不是 單引號,而是 鍵盤 Esc下面的那個標點
三、添加好友功能之監聽message消息
在數據庫加入了一個 帶有list和userid的數據,所以在userid這個人登陸小程序之后,就應該可以看到有沒有人給他發送消息了
並且還是要實時的更新,就是這個人在登陸狀態的話,也可以直接收到了,也就是要實現實時的監聽數據庫中list的實時變化了
在開發者文檔中:雲開發-》實時數據的推送:
https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/database/realtime.html
(它的意思就是我們可以監聽到數據庫發送的變化
可以直接查看demo
const db = wx.cloud.database() const watcher = db.collection('todos') // 按 progress 降序 .orderBy('progress', 'desc') // 取按 orderBy 排序之后的前 10 個 .limit(10) .where({ team: 'our dev team' }) .watch({ onChange: function(snapshot) { console.log('docs\'s changed events', snapshot.docChanges) console.log('query result snapshot after the event', snapshot.docs) console.log('is init data', snapshot.type === 'init') }, onError: function(err) { console.error('the watch closed because of error', err) } }) // ... // 等到需要關閉監聽的時候調用 close() 方法 watcher.close()
我們可以在user頁面中進行檢測即可,也就是在登陸之后進行檢測了
我們創建了一個方法 getMessage()。只要用戶登陸了之后就可以進行觸發了,在onReady里面的登陸成功代碼之后即可了
也就是在數據庫定位到uuseid是這個用戶的數據之后,得到了之后就可以用watch方法來進行監聽了
getMessage(){ db.collection('message').where({ userId : app.userInfo._id }).watch({ onChange: function (snapshot) { console.log(snapshot); } }); }
這個onChange就是進行監聽的函數了,我們在遇到陌生的一定要傳入參數的函數的時候,最好是把這個參數用console.log打印出來看看我們的想要的數據在哪個位置里面的
注意了:如果是按照上面這樣的話,是會報錯的,以為缺少了錯誤返回的 onError函數的,示例的demo里面的格式是怎么樣的,最好就用怎么樣的
不然可能都是會報錯的
但是會發現,我們沒拿到有用的數據
就可以用多賬號來調試一下了
(這里用的多賬號最好還是用真實的賬號把,因為虛擬的出現的問題挺大的)
(然后還要設置給message權限是第一個,允許全部人看的那種,才可以看到在別的賬號上的加好友信息的
在別的賬號上面的話就可以看到打印的信息了,可以看到我們得到的消息其實是挺亂的,所以最好用判斷來搞一下
測試之后會發現,得到的 snapshot 數據中有一個 docChanges 數組的,只要有申請,就會有顯示了
所以我們可以通過對數組的長度進行一個判斷
然后再對這個list進行判斷,通過長度來進行判斷,如果有長度的話說明就有消息了
有消息的話就要給用戶一個提示,就是在下面的tabbar中的消息圖標右上角添加一個紅色的小點
===其實這個功能在微信小程序中其實就已經幫我們設計好了
微信文檔-》API-》界面-》tabbar-》wx.showTabBarRedDot
https://developers.weixin.qq.com/miniprogram/dev/api/ui/tab-bar/wx.showTabBarRedDot.html
它需要定義一個index屬性,來指定放紅點的是tabbar中的哪一項的(它是從0開始的,所以我們設置為2即可了)
也就是說這個用戶拿到了這個list之后,通過這個list的長度來判斷有沒有消息,然后設置紅點提示,並且還要把這個得到的list用到消息頁面中去的
所以就涉及到了,怎么把這個得到的list共享到消息中去,這個和之前的userInfo是類似的,點開全局的app.js
this.userMessage = []
這里創立的是一個數組來的,不是對象了
然后在user.js里面,判斷這個得到的list的長度,設置tabbar上面的小紅心,然后把得到的list賦值給全局的userMessage
但是如果檢測到這個list是空的話,就要把在tabbar上面的小紅心取消掉了
**然后還要讓我們全局的userMessage等於一個空的數組即可了
這樣,這個監聽的函數就完成了:
getMessage(){ db.collection('message').where({ userId : app.userInfo._id }).watch({ onChange: function (snapshot) { // console.log(snapshot) if( snapshot.docChanges.length){ //這里就可以直接拿到message里面所對應的消息列表了 let list = snapshow.docChanges[0].doc.list; if( list.length ){ wx.showTabBarRedDot({ index: 2, }); app.userMessage = list; } else{ wx.hideTabBarRedDot({ index: 2, }) app.userMessage = []; } } }, onError: function (err) { console.error('the watch closed because of error', err) } }); }
然后因為watch是實時監聽的,我們在數據庫里面把給的信息刪掉的話
這個紅點也就會消失了
這就是因為正在實時的監聽着
四、下面搞的就是如何把共享的userMessage在消息頁面中渲染出來
===消息頁面和removeList組件布局
首先 切換編譯模式到消息頁面中,先做布局
<view class="message"> <view> <text>暫無消息:</text> </view> <view> <text>消息列表:</text> <view>第一條消息</view> <view>第二條消息</view> </view> </view>
之后就是先判斷有沒有消息。所以就要在js看i嗎添加一個東西,這里添加的是一個userMessage數組,就是用來接收我們的那個全局的list的,
如果這個數組是空的話,說明就是沒有消息了,反之,所以就可以通過這個來進行判斷了
**之后就要測試一下message這個頁面里面文件的生命周期了
這就是為了測試,在tabbar中的生命周期是怎么樣的
在message.js里面
onReady: function () {
console.log(1)
},
/**
* 生命周期函數--監聽頁面顯示
*/
onShow: function () {
console.log(2)
},
在點擊了下main的tabbar的圖標之后,
打印的結果:
但是當我們幾點了個人頁面之后,再點擊消息頁面的時候,只打印了2
也就是說在tabbar里面的onreay並不會再次的觸發(但是普通頁面的onreay是會被再次觸發的),但是他也是會觸發onshow的
所以基於這個就可以在onshow中添加東西,來監聽現在的消息變化情況了
因為如果想要進入消息頁面的話,就得先登陸,所以這力又要一個判斷了,如果沒登陸得話,就讓他跳轉到登陸頁面去的
(這個功能就和我們的detail里面很像的,就可以直接COPY過來了)

const app = getApp() Page({ /** * 頁面的初始數據 */ data: { userMessage : [], logged : false }, /** * 生命周期函數--監聽頁面加載 */ onLoad: function (options) { }, /** * 生命周期函數--監聽頁面初次渲染完成 */ onReady: function () { // console.log(1) }, /** * 生命周期函數--監聽頁面顯示 */ onShow: function () { // console.log(2) if( app.userInfo._id ){ this.setData({ logged : true, userMessage : app.userMessage }); }else{ wx.showToast({ title: '請先登陸', duration: 2000, // 然后不要讓它顯示圖標 icon: 'none', success: () => { // 如果成功的話就直接跳轉到我的頁面去 // 但是注意了這里不能用 navigator to,因為它主要是跳轉 // 普通的頁面,而這里“我的頁面”其實是同tabbar來進行配置的 setTimeout(() => { wx.switchTab({ url: '/pages/user/user', }) }, 2000); } }) } }, /** * 生命周期函數--監聽頁面隱藏 */ onHide: function () { }, /** * 生命周期函數--監聽頁面卸載 */ onUnload: function () { }, /** * 頁面相關事件處理函數--監聽用戶下拉動作 */ onPullDownRefresh: function () { }, /** * 頁面上拉觸底事件的處理函數 */ onReachBottom: function () { }, /** * 用戶點擊右上角分享 */ onShareAppMessage: function () { } })
雖然我們吧list引入進來了,下面就是吧這個list顯示出來了
我們用虛擬賬號,給我的主號提交了兩個申請來進行測試了
之后在message.wxml中對我們的信息進行打印:
<!--miniprogram/pages/message/message.wxml--> <view class="message" wx:if="{{ logged }}"> <view wx:if="{{ !userMessage.length }}"> <text class="message-text">暫無消息:</text> </view> <view wx:else> <text class="message-text">消息列表:</text> <view wx:for="{{ userMessage }}" wx:key="{{index}}">{{item}}</view> </view> </view>
我們還要進行優化,就是可以得到一個列表,有頭像有昵稱,等信息的,別還要有刪除的功能的
為了練習一下組件的功能,雖然這個刪除的功能可以直接在這個文件里面寫,但是我們還是吧這個刪除變成一個組件的形式l
新建一個removeList的刪除組件,然后就是找到message的JSON文件引入這個組件
這個組件其實是可以拖拽的?
在文檔-》組件-》視圖容器 movable-area和movable-view相互配合的
demo:
<movable-area> <movable-view x="{{x}}" y="{{y}}" direction="all">text</movable-view> </movable-area>
我們設置的結構和樣式:
<!--components/removeList/removeList.wxml--> <movable-area class="area"> <movable-view class="view">小喵喵</movable-view> </movable-area>
/* components/removeList/removeList.wxss */ .area{width:800rpx; height: 150rpx; margin: 20rpx ; position: relative;background: blue;} .view{width:630rpx; height:100%; background: red;position: absolute;left:150rpx;top:0; line-height: 150rpx;text-indent: 10rpx;}
效果;
但是這個時候還是不能進行拖拽的,其中的direction定義的就是拖拽的方向
添加了這個屬性之后:
<!--components/removeList/removeList.wxml--> <movable-area class="area"> <movable-view direction="horizontal" class="view">小喵喵</movable-view> </movable-area>
就可以進行拖拽了
注意;下面設置的z-Index是在設置級別,z-index大的會覆蓋在小的上面的
<!--components/removeList/removeList.wxml--> <movable-area class="area"> <movable-view direction="horizontal" class="view">小喵喵</movable-view> <image src="" /> <view class="delete">刪除</view> </movable-area>
/* components/removeList/removeList.wxss */ .area{width:800rpx; height: 150rpx; margin: 20rpx ; position: relative;border-bottom: 1px #cdcdcd dashed} .view{width:630rpx; height:100%; position: absolute;left:150rpx;top:0; line-height: 150rpx;text-indent: 10rpx;z-index: 2;} image{ width: 100rpx; height: 100rpx; border-radius: 50%; position: absolute; left: 0; top: 0; z-index: 1; } .delete{ width: 200rpx; height: 150rpx; background: red; color: white; position: absolute; right: 0; top: 0; z-index: 1; }
但是得到的效果是:
會發現不管怎么拖拉,都擋不住后面的刪除--原因就是class==view這塊沒加背景色,雖然層級夠了
給他在wxss里面添加一個 background:white即可了
刪除那個文字要居中的話,
.delete{ width: 170rpx; height: 100rpx; background: red; color: white; position: absolute; right: 0; top: 0; z-index: 1; line-height: 100rpx; }
效果圖: