1. 程式人生 > >微信小程式開發入門第七章:收藏、評論、點贊及計數功能

微信小程式開發入門第七章:收藏、評論、點贊及計數功能

    本章內容有一定的難度,但其中的技巧和知識還是很豐富的。本章通過編寫幾乎所有內容型應用都會附帶的“評論”“點贊”“閱讀計數”“收藏”等功能,來學習使用小程式的互動反饋元件、快取的應用、圖片選擇和預覽、遮蔽關鍵字、錄音、拍照以及播放錄音等功能

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.js
onUpTap: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並將這種思路應用到自己的專案中。