微信小程式開發入門第七章:收藏、評論、點贊及計數功能
本章內容有一定的難度,但其中的技巧和知識還是很豐富的。本章通過編寫幾乎所有內容型應用都會附帶的“評論”“點贊”“閱讀計數”“收藏”等功能,來學習使用小程式的互動反饋元件、快取的應用、圖片選擇和預覽、遮蔽關鍵字、錄音、拍照以及播放錄音等功能
7.1 收藏、評論、點贊、計數功能準備工作
7.1 收藏、評論、點贊、計數功能準備工作
接下來我們將要連續實現4個非常有意思的功能,這些功能在內容型應用中是非常常見的,分別是收藏、點贊、評論和計數。
我們先來編寫收藏、評論和點讚的功能按鈕。閱讀計數是一項被動功能,無須使用者有意識地主動觸發。在post-detail.wxml中新增一段工具欄程式碼。
程式碼清單 7-1 編寫3個功能的功能按鈕 post-detail.wxml
<!--pages/post/post-detail/post-detail.wxml--> <view class="container"> <image class="head-image" src="{{post.postImg}}"></image> <text class="title">{{post.title}}</text> <view class="author-date"> <view class="author-box"> <image class="avatar" src="{{post.avatar}}"></image> <text class="author">{{post.author}}</text> </view> <text class="date">{{post.dataTime}}</text> </view> <text class="detail">{{post.detail}}</text> </view> <view class="tool"> <view class="tool-item" catchtap='onUpTop' data-post-id="{{post.postId}}"> <image src="/images/icon/wx_app_like.png"></image> <text>{{post.upNum}}</text> </view> <view class="tool-item comment" catchtap='onCommentTap' data-post-id="{{post.postId}}"> <image src="/images/icon/wx_app_message.png"></image> <text>{{post.commentNum}}</text> </view> <view class="tool-item" catchtap='onCollectionTap' data-post-id="{{post.postId}}"> <image src="/images/icon/wx_app_collected.png"></image> <text>{{post.upNum}}</text> </view> </view>
在post-detail.wxml頁面的container中添加了一段<view class="tool">的相關程式碼。該程式碼實現了收藏、評論和點贊3個功能按鈕。每個功能按鈕都綁定了對應的點選事件,注意view元件上的catchtap屬性。除此之外,我們還在每個功能按鈕上使用data-post-id綁定了當前文章的id號。
upNum、commentNum和collectionNum等資料已經在5.13小節中全部新增到了data.js檔案中。
接著編寫3個功能按鈕的樣式
程式碼清單 7-2 編寫3個功能按鈕的樣式 post-detail.wxss
.tool{
height: 64rpx;
text-align: center;
line-height: 64rpx;
margin: 20rpx 28rpx 20rpx 0;
}
.tool-item{
display: inline-block;
vertical-align: top;
margin-right: 30rpx;
}
.tool-item image{
height: 30rpx;
width: 30rpx;
vertical-align: -3px;
margin-right: 10rpx;
}
.comment image{
transform: scale(.85);
}
儲存重新整理後,3個功能按鈕將出現在post-detail頁面的正下方,如圖7-1所示。
圖7-1 3個功能按鈕的樣式和位置
7.2 文章收藏功能
7.2 文章收藏功能
我們首先來實現文章收藏功能。文章收藏功能需要記錄兩個變數值:
自己是否收藏了文章。如果自己收藏了,那麼需要將收藏的圖片更換為已收藏。
所有使用者收藏文章的總數量。需要注意的是,由於我們的資料庫只在本地,無法多次收藏同一篇文章,所以收藏數量永遠只能在初始數量的基礎上+1或者-1,分別對應取消收藏和點選收藏兩種狀態。但在真實的專案中,這個收藏數量卻是要受到所有使用者取消、收藏文章動作影響的。同樣的情況也會出現在“文章點贊”這個功能裡。
當頁面從post跳轉到post-detail時,我們就需要知道該文章是否已被使用者收藏。在data.js中,我們使用collectionStatus這個屬性表示文章是否已被收藏,這個變數的型別是Boolean。那麼如何根據collectionStatus這個變數的取值來動態切換收藏圖示呢?
熟悉傳統Web開發的讀者很容易想到用jQuery獲取image標籤,再動態地設定image的src屬性。再次強調,小程式沒有dom,一切都是資料繫結,請拋棄dom的思維方式。
7.2.1 條件渲染:wx:if與wx:else
collectionStatus只有兩種取值:true或者false。我們需要做的是,當collectionStatus為false時,顯示圖7-2未收藏狀態的圖示,而當collectionStatus為true時,顯示圖7-3收藏狀態的圖示。
以上需求是不是就是程式設計中非常經典的if else?如果wxml元件也像js程式碼一樣有if else就可以解決動態顯示收藏圖片的問題。下面來看看如何實現這個功能。
小程式提供了wx:if與wx:else來實現條件渲染。當變數為true時,執行wx:if,否則將執行wx:else。修改收藏按鈕的wxml程式碼如下:
程式碼清單 7-3 條件渲染 post-detail.wxml
<view class="tool-item" catchtap='onCollectionTap' data-post-id="{{post.postId}}">
<image wx:if="{{post.collectionStatus}}" src="/images/icon/wx_app_collected.png"></image>
<image wx:else src="/images/icon/wx_app_collect.png"></image>
<text>{{post.collectionNum}}</text>
</view>
上述程式碼中我們添加了兩個image元件,分別是收藏和未收藏圖片。這兩個image元件各有一個wx:if和wx:else屬性。當post.collectionStatus為true時將顯示wx_app_collected.png圖片,而當post.collectionStatus為false時將顯示wx_app_collect.png圖片。
由於我們已經在data.js檔案中將部分文章的收藏狀態設定為true,因此儲存並執行專案,發現所有collectionStatus為true的文章,其收藏圖片都將顯示wx_app_collected.png,如圖7-4所示。
圖7-4 顯示wx_app_collected.png
wx:if與wx:else的條件渲染在小程式中被大量使用,不僅僅被用來做圖片的更換,還可以用來控制元素的顯示和隱藏。
wx:if可以被單獨使用,並不一定要同wx:else一起使用。
除此之外,條件渲染還可以做多級別的if else,如程式碼清單7-4的示例程式碼所示。
如果變數length的取值大於5,那麼將顯示數字1。
如果變數length的取值大於2且小於等於5,那麼將顯示數字2。
以上條件都不滿足,就顯示數字3。
你還可以新增更多的elif分支,以實現更多級別的條件判斷。
7.2.2 實現收藏點選功能
在7.2.1小節中,我們僅僅是在post-detail頁面載入時讀取了該文章對於當前使用者是否為收藏狀態,並正確地設定和顯示了這個狀態。
在這個小節中,我們將實現使用者點選圖片進行文章的收藏和取消收藏功能。首先我們繼續完善DBPost這個資料庫操作類。在DBPost類中新增一個方法,用以處理文章的收藏操作。
程式碼清單 7-5 新增處理文章收藏的方法 DBPost.js
//收藏文章
collect()
{
return this.updatePostData('collect');
}
該方法中呼叫了DBPost類的updatePostData方法,這個方法我們還沒有編寫。
在DBPost類中新增updatePostData方法。該方法是處理點贊、評論、收藏、閱讀的核心方法。
程式碼清單 7-6 新增updatePostData方法 DBPost.js//更新本地的點贊、評論資訊、收藏、閱讀量
updatePostData(category){
var itemData = this.getPostItemById(),
postData = itemData.data,
allPostData = this.getAllPostData();
switch(category){
case 'collect':
//處理收藏
if(!postData.collectionStatus){
//如果當前狀態是未收藏
postData.collectionNum++;
postData.collectionStatus = true;
}else{
//如果當前狀態是已收藏
postData.collectionNum--;
postData.collectionStatus = false;
}
break;
default:break;
}
//更新快取資料庫
allPostData[itemData.index] = postData;
this.execSetStorageSync(allPostData);
return postData;
}
我們目前僅處理collect這一種操作,後續我們將繼續在程式碼清單7-6的switch case中新增評論、閱讀數、點贊等處理分支。
這樣,DBPost就具備了處理文章收藏的能力。當用戶點選收藏按鈕後,在點選事件函式中呼叫DBPost的collect方法即可。
處理文章收藏動作的事件函式是onCollectionTap,這個事件函式已在程式碼清單7-1中被註冊在了收藏功能按鈕上。我們只需要在post-detail.js中編寫這個方法即可
程式碼清單 7-7編寫onCollectionTap方法 post-detail.js
nCollectionTap:function(event){
//dbpost物件已在onLoad函式中被儲存到了this變數中,無需再次例項化
var newData = this.dbPost.collect();
//從新繫結資料,注意,不要將整個newData全部作為setData的引數,應當有選擇的更新部分資料
this.setData(
{
'post.collectionSataus':newData.collectionStatus,
'post.collectionNum':newData.collectionNum
}
)
}
7.2.3 互動反饋wx:showToast
現在,我們已經實現了文章的收藏與取消收藏功能,但收藏功能的體驗並不好,使用者在收藏和取消收藏後沒有任何互動反饋提示。
小程式提供了一些互動反饋API來幫助開發者處理互動相關的問題。目前,小程式提供了以下4個互動反饋API:
wx.showToast
wx.hideToast
wx.showModal
wx.showActionSheet
我們選用wx.showToast(object)來製作文章收藏功能的互動反饋。
程式碼清單 7-8 文章收藏功能的互動反饋 post-detail.js//互動反饋
wx.showToast({
title:newData.collectionStatus?"收藏成功":"收藏取消",
duration:1000,
icon:"sucess",
make:true
})
其中,object引數的title屬性用於設定提醒訊息的內容;duration設定提醒的自動消失時間,最長10000毫秒,預設值為1500毫秒;icon可以設定一個小圖示,其取值只能是success和loading;mask指定是否顯示透明的蒙層,以防止觸控穿透,預設值為false。
mask主要用來防止使用者連續點選收藏按鈕。開發者可執行嘗試將mask設定為true和false時的不同效果:當mask為true時連續點選收藏圖示,圖示不會連續做出收藏/取消收藏的響應;當mask為false時,就會不停地響應使用者的點選操作。
wx.showToast的效果如圖7-5所示。
圖7-5 wx.showToast效果
7.3 文章點贊功能
7.3 文章點贊功能
文章點贊功能的實現思路同收藏幾乎是一樣的。首先在DBPost.js中增加點讚的方法。
程式碼清單7-9 新增處理點贊操作的方法 DBPost.js
//點贊或取消點贊
up(){
return this.updatePostData('up');
}
接著在DBPost的updatePostData方法中處理當case為up時的情況。下面給出updatePostData的全部程式碼。
程式碼清單 7-10 增加case為up時的處理方法 DBPost.js
//更新本地的點贊、評論資訊、收藏、閱讀量
updatePostData(category){
var itemData = this.getPostItemById(),
postData = itemData.data,
allPostData = this.getAllPostData();
switch(category){
case 'collect':
//處理收藏
if(!postData.collectionStatus){
//如果當前狀態是未收藏
postData.collectionNum++;
postData.collectionStatus = true;
}else{
//如果當前狀態是已收藏
postData.collectionNum--;
postData.collectionStatus = false;
}
break;
case 'up':
if(!postData.upStatus){
postData.upNum++;
postData.upStatus = true;
}else{
postData.upNum--;
postData.upStatus = false;
}
break;
default:break;
}
//更新快取資料庫
allPostData[itemData.index] = postData;
this.execSetStorageSync(allPostData);
return postData;
}
程式碼清單7-10同程式碼清單7-6相比,僅僅增加了case為'up'時的這段程式碼。很明顯,我們可以看到處理點讚的邏輯同處理收藏時的邏輯幾乎一樣:改變upStatus的狀態,並對upNum這個計數變數做相應的增減操作。我們編寫完DBPost中關於點讚的介面後,接著編寫post-detail.js和post-detail.wxml中關於點讚的相關程式碼。
程式碼清單 7-11 編寫onUpTap方法 post-detail.jsonUpTap:function(event){
var newData = this.dbPost.up();
this.setData({
'post.upStatus':newData.upStatus,
'post.upNum':newData.upNum,
})
wx.showToast({
title: newData.upStatus ? "點贊成功" : "點贊取消",
duration: 1000,
icon: "sucess",
make: true
})
onUpTap方法響應使用者點讚的動作。當用戶點選點贊按鈕後,onUpTap方法將呼叫DBPost的up方法並將返回的最新資料使用this.setData更新。
類似於收藏功能,我們還需要使用條件渲染wx:if改寫wxml中的點贊按鈕。
程式碼清單 7-12 點贊功能的條件渲染 post-detail.wxml<view class="tool-item" catchtap='onUpTap' data-post-id="{{post.postId}}">
<image wx:if="{{post.upStatus}}" src="/images/icon/wx_app_liked.png"></image>
<image wx:else src='/images/icon/wx_app_like.png'></image>
<text>{{post.upNum}}</text>
</view>
以上程式碼將在post.upStatus為true時顯示wx_app_liked.png,當post.upStatus為false時顯示wx_app_like.png。
在編寫完以上程式碼後,儲存執行專案,點選點贊按鈕,圖片會不斷切換,點贊數也將相應地+1或者-1。
很多開發者可能還不太習慣使用資料繫結的方式來做樣式、狀態的切換,但資料繫結的寫法確實非常簡化、方便。我們只需要在js中改變各類變數的狀態和值,前端元件就會響應我們的操作,動態地做出變化。
7.4 本地快取的重要性及應用舉例
提供本地的key&value快取機制是小程式的一大特點,善用本地快取將可以極大地改善客戶端的體驗與伺服器的效能。
前幾個小節中,我們大量地使用了本地快取來模擬伺服器的資料庫。這樣做一方面是因為我們並沒有真實的伺服器,必須依靠客戶端的快取能力來記錄資料;另一方面是因為即使在真實的專案中我們擁有自己的遠端伺服器,也依然需要在客戶端管理本地快取。
舉個例子,如果我們要實現一個城市列表外掛,就必然要獲取全國所有城市的資訊。全國大概有600多個城市,這麼大的資料量難道每次開啟這個外掛都要去伺服器取城市資料嗎?這些城市的資料相對非常穩定,並不會頻繁變化,每次都去伺服器載入是對流量和伺服器效能的嚴重消耗。
所以,最好的解決方案就是將城市資料儲存在本地快取中,而不是每次都去伺服器請求資料。
在一個高效能的產品中,快取的重要性是不言而喻的。建議開發者將本地快取視作一個本地的key&value資料庫,並封裝一些類和公共方法,提供給專案中的各個呼叫方。最好不要讓getStorage、setStorage等方法充斥在專案的每一個角落。
Orange Can專案中的DBPost類就是一個不錯的示例,它實現了對快取的良好管理,並向呼叫方提供了一系列可讀性非常強的API。建議開發者參考DBPost並將這種思路應用到自己的專案中。