1.6 收藏、評論、點贊、計數(shù)功能準備工作

1、收藏、評論、點贊、計數(shù)功能準備工作

編寫收藏、評論、點贊的功能按鈕。計數(shù)功能是一個被動功能,無須用戶有意識的主動觸發(fā)。

1.1 編寫3個功能的功能按鈕

post-detail.wxml
<view class='tool'>
  <view class='tool-item' catchtap='onUpTap' 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_collect.png'></image>
    <text>{{post.collectionNum}}</text>
  </view>
</view>

1.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(0.85);
}
image.png
  • 屬性注意點

1)transform: scale()屬性


image.png
image.png

2)display: inline-block;屬性


image.png
image.png

2、文章收藏功能

文章收藏功能需要記錄兩個變量值:
1)根據(jù)是否已經(jīng)收藏更換照片、
2)收藏數(shù)量的變化

2.1 條件渲染:wx:if 與 wx:else

小程序提供了wx:if 與 wx:else來實現(xiàn)條件渲染。當(dāng)變量為true時,執(zhí)行wx:if,否則將執(zhí)行wx:else

2.1.1 條件渲染:wx:if 與 wx:else
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_collected.png'></image>
    <text>{{post.collectionNum}}</text>
  </view>
image.png
2.1.2 多級別 if else
<view wx:if="{{length > 5}}">1</view>
<view wx:elif="{{length > 2}}">2</view>
<view wx:else>3</view>

2.2 實現(xiàn)收藏點擊功能

2.2.1 添加處理文章收藏的方法

首先完善數(shù)據(jù)庫工具類的操作

DBPost.js

  //收藏文章
  collect() {
    return this.updatePostData("collect");
  }

  //更新本地的點贊、評論信息、收藏、閱讀量
  updatePostData(category) {
    var itemData = this.getPostItemById(),
      postData = itemData.data,
      allPostData = this.getAllPostData();

    switch (category) {
      case 'collect':
        //處理收藏
        if (!postData.collectionStatus) {
          //如果當(dāng)前狀態(tài)是未收藏
          postData.collectionNum++;
          postData.collectionStatus = true;
        } else {
          //如果當(dāng)前狀態(tài)是收藏
          postData.collectionNum--;
          postData.collectionStatus = false;
        }
        break;
      default:
        break;
    }

2.2.2 編寫onCollectionTap方法

首先完善數(shù)據(jù)庫工具類的操作

post-detail.js
  onCollectionTap:function(event){
    var newData = this.dbPost.collect();

    //重新綁定數(shù)據(jù)
    //應(yīng)該選擇更新部分數(shù)據(jù)
    this.setData({
      'post.collectionStatus':newData.collectionStatus,
      'post.collectionNum': newData.collectionNum
    });
  }

2.3 交互反饋wx:showToast

小程序提供了一些交互反饋API來幫助開發(fā)者處理交互相關(guān)的問題,目前主要有如下幾個:


image.png
2.3.1 文章收藏功能的交互反饋
post-detail.js
    wx.showToast({
      title: newData.collectionStatus? '收藏成功':'取消成功',
      duration:1000,
      icon:'success',
      mask:true
    })

-參數(shù)說明


image.png
image.png

2.3 文章點贊功能

這個功能跟之前文章收藏功能基本寫法是一樣的

2.3.1 添加處理點贊操作的方法
DBPost.js

  //點贊或者取消點贊
  up() {
    var data = this.updatePostData('up');
    return data;
  }

  //更新本地的點贊、評論信息、收藏、閱讀量
  updatePostData(category) {
    var itemData = this.getPostItemById(),
      postData = itemData.data,
      allPostData = this.getAllPostData();

    switch (category) {
      case 'collect':
        //處理收藏
        if (!postData.collectionStatus) {
          //如果當(dāng)前狀態(tài)是未收藏
          postData.collectionNum++;
          postData.collectionStatus = true;
        } else {
          //如果當(dāng)前狀態(tài)是收藏
          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;
    }

    //更新緩存數(shù)據(jù)庫
    allPostData[itemData.index] = postData;
    this.execSetStorageSync(allPostData);
    return postData;
  }

2.3.2 編寫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.collectionStatus ? '點贊成功' : '取消成功',
      duration: 1000,
      icon: 'success',
      mask: false
    })
  },

2.3.3 點贊功能的條件渲染
post-detail.wxml
<view class='tool'>
  <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>
image.png

2.4 本地緩存的重要性及應(yīng)用舉例

提供本地的key&value緩存機制是小程序的一大特點,善用本地緩存可以極大地改善客戶端的體驗與服務(wù)器的性能。

在一個高性能的產(chǎn)品中,緩存的重要性是不言而喻的,建議開發(fā)者將本地緩存視作為一個本地的key&value數(shù)據(jù)庫,并封裝一些類和公用方法,提供給項目中的各個調(diào)用方,最好不要讓getStorage 、setStorage等方法充斥在項目的每一個角落

2.5 支持文字、圖片、拍照、語音上傳的文章評論

2.5.1 注冊post-comment頁面
app.json
image.png
2.5.2 onCommentTap方法
post-detail.js
  onCommentTap: function (event){
    var id = event.currentTarget.dataset.postId;
    wx.navigateTo({
      url: '../post-comment/post-comment?id='+id
    })
  },

2.6 文章評論頁面的實現(xiàn)步驟與思路

2.6.1 思路

1)加載并顯示當(dāng)前文章已存在的評論
2)添加新評論的功能

2.6.2 步驟

1)在post-comment.js中獲取并綁定文章評論數(shù)據(jù)
2)在post-comment 頁面的wxml和wcss顯示文章評論數(shù)據(jù)
3)編寫添加新評論的功能

2.7 獲取并綁定文章評論數(shù)據(jù)

2.7.1 獲取評論數(shù)據(jù)
post-comment.js
import{DBPost} from '../../../db/DBPost.js'

Page({

  /**
   * 頁面的初始數(shù)據(jù)
   */
  data: {
  
  },

  /**
   * 生命周期函數(shù)--監(jiān)聽頁面加載
   */
  onLoad: function (options) {
    var postId = options.id;
    this.dbPost = new DBPost(postId);
    var comments = this.dbPost.getCommentData();

    console.log('comments==' + comments)

    //綁定評論數(shù)據(jù)
    this.setData({
      comments:comments
    })
  },

 
})
2.7.2 編寫獲取文章評論的方法
DBPost.js
  //編寫獲取文章評論的方法
  getCommentData() {
    var itemData = this.getPostItemById().data;
    //按時間減序排列評論
    itemData.comments.sort(this.compareWithTime);
    var len = itemData.comments.length,
      comment;

    for (var i = 0; i < len; i++) {
      comment = itemData.comments[i];
      comment.create_time = util.getDiffTime(comment.create_time, true);
    }
    return itemData.comments;
  }
2.7.3 compareWithTime方法
DBPost.js
 compareWithTime(value1, value2) {
    var flag = parseFloat(value1.create_time) - parseFloat(value2.create_time);

    if (flag < 0) {
      return 1;
    } else if (flag > 0) {
      return -1;
    } else {
      return 0;
    }
  }
2.7.4 getDiffTime方法
util.js
/*
 *根據(jù)客戶端的時間信息得到發(fā)表評論的時間格式
 *多少分鐘前,多少小時前,然后是昨天,然后再是月日
 * Para :
 * recordTime - {float} 時間戳
 * yearsFlag -{bool} 是否要年份
 */
function getDiffTime(recordTime, yearsFlag) {
  if (recordTime) {
    recordTime = new Date(parseFloat(recordTime) * 1000);
    var minute = 1000 * 60,
      hour = minute * 60,
      day = hour * 24,
      now = new Date(),
      diff = now - recordTime;
    var result = '';
    if (diff < 0) {
      return result;
    }
    var weekR = diff / (7 * day);
    var dayC = diff / day;
    var hourC = diff / hour;
    var minC = diff / minute;
    if (weekR >= 1) {
      var formate = 'MM-dd hh:mm';
      if (yearsFlag) {
        formate = 'yyyy-MM-dd hh:mm';
      }
      return recordTime.format(formate);
    }
    else if (dayC == 1 || (hourC < 24 && recordTime.getDate() != now.getDate())) {
      result = '昨天' + recordTime.format('hh:mm');
      return result;
    }
    else if (dayC > 1) {
      var formate = 'MM-dd hh:mm';
      if (yearsFlag) {
        formate = 'yyyy-MM-dd hh:mm';
      }
      return recordTime.format(formate);
    }
    else if (hourC >= 1) {
      result = parseInt(hourC) + '小時前';
      return result;
    }
    else if (minC >= 1) {
      result = parseInt(minC) + '分鐘前';
      return result;
    } else {
      result = '剛剛';
      return result;
    }
  }
  return '';
}

2.7.5 在Date原型鏈上新增format方法
util.js
/*
 *拓展Date方法。得到格式化的日期形式
 *date.format('yyyy-MM-dd'),date.format('yyyy/MM/dd'),date.format('yyyy.MM.dd')
 *date.format('dd.MM.yy'), date.format('yyyy.dd.MM'), date.format('yyyy-MM-dd HH:mm')
 *使用方法 如下:
 *                       var date = new Date();
 *                       var todayFormat = date.format('yyyy-MM-dd'); //結(jié)果為2015-2-3
 *Parameters:
 *format - {string} 目標格式 類似('yyyy-MM-dd')
 *Returns - {string} 格式化后的日期 2015-2-3
 *
 */
(function initTimeFormat() {
  Date.prototype.format = function (format) {
    var o = {
      "M+": this.getMonth() + 1, //month
      "d+": this.getDate(), //day
      "h+": this.getHours(), //hour
      "m+": this.getMinutes(), //minute
      "s+": this.getSeconds(), //second
      "q+": Math.floor((this.getMonth() + 3) / 3), //quarter
      "S": this.getMilliseconds() //millisecond
    }
    if (/(y+)/.test(format)) format = format.replace(RegExp.$1,
      (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o) if (new RegExp("(" + k + ")").test(format))
      format = format.replace(RegExp.$1,
        RegExp.$1.length == 1 ? o[k] :
          ("00" + o[k]).substr(("" + o[k]).length));
    return format;
  };
})()

2.7.6 添加module.exports
util.js
module.exports = {
  getDiffTime: getDiffTime
}
2.7.7 引用util模塊
DBPost.js
var util = require('../util/util.js')
image.png

2.8 顯示文章評論數(shù)據(jù)

2.8.1 獲取評論數(shù)據(jù)wxml代碼
post-comment.wxml
<!--pages/post/post-comment/post-comment.wxml-->
<view class='comment-detail-box'>
  <view classs='comment-main-box'>
    <view class='comment-title'>評論......(共{{comments.length}}條)</view>
    <block wx:for="{{comments}}" wx:for-item="item" wx:for-index="idx">
      <view class='comment-item'>
        <view class='comment-item-header'>
          <view class='left-img'>
            <image src='{{item.avatar}}'></image>
          </view>
          <view class='right-user'>
            <text class='user-name'>{{item.username}}</text>
          </view>
        </view>
        <view class='comment-body'>
          <view class='comment-text' wx:if="{{item.content.text}}">
            <text>{{item.content.txt}}</text>
          </view>
          <view class='comment-voice' wx:if="{{item.content.audio && item.content.audio.url}}">
          <view data-url='{{item.content.audio.url}}' class='comment-voice-item' catchtap="playAudio">
          <image src='/images/icon/wx_app_voice.png' class='voice-play'></image>
          <text>{{item.content.audio.timeLen}}</text>
          </view>
          </view>
          <view class='comment-img' wx:if="{{item.content.img.length!=0}}">
          <block wx:for="{{item.content.img}}" wx:for-item="img">
          <image src='{{img}}' mode='aspectFill'></image>
          </block>
          </view>
        </view>
        <view class='comment-time'>{{item.create_time}}</view>
      </view>
    </block>
  </view>
</view>
2.8.2 添加評論列表的樣式
post-comment.wxss
/* pages/post/post-comment/post-comment.wxss */

.comment-detail-box {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
   overflow-y: hidden; 
}

.comment-main-box {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 100rpx;
  right: 0;
  overflow-y: auto;
}

.comment-title {
  height: 60rpx;
  line-height: 60rpx;
  font-size: 28rpx;
  color: #212121;
  border-bottom: 1px solid #ccc;
  margin-left: 24rpx;
  padding: 8rpx 0;
  font-family: Microsoft YaHei;
}

.comment-item {
  margin: 20rpx 0 20rpx 24rpx;
  padding: 24rpx 24rpx 24rpx 0;
  border-bottom: 1rpx solid #f2e7e1;
}

.comment-item:last-child {
  border-bottom: none;
}

.comment-item-header {
  display: flex;
  flex-direction: row;
  align-items: center;
}

.comment-item-header .left-img image {
  height: 80rpx;
  width: 80rpx;
}

.comment-item-header .right-user {
  margin-left: 30rpx;
  line-height: 80rpx;
}

.comment-item-header .right-user text {
  font-size: 26rpx;
  color: #212121;
}

.comment-body {
  font-size: 26rpx;
  line-height: 26rpx;
  color: #666;
  padding: 10rpx 0;
}

.comment-text text {
  line-height: 50rpx;
}

.comment-voice-item {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 200rpx;
  height: 64rpx;
  border: 1px solid #ccc;
  background-color: #fff;
  border-radius: 6rpx;
}

.comment-voice-item .voice-play {
  height: 64rpx;
  width: 64rpx;
}

.comment-voice-item text {
  margin-left: 60rpx;
  color: #212121;
  font-size: 22rpx;
}

.comment-img {
  margin: 10rpx 0;
}

.comment-img image {
  max-width: 32%;
  margin-right: 10rpx;
  width: 220rpx;
  height: 22orpx;
}

.comment-time {
  margin-top: 10rpx;
  color: #ccc;
  font-size: 24rpx;
}

image.png
  • 樣式注意點:
    1)overflow-y: hidden


    image.png
image.png

2).comment-item:last-child


image.png

2.9 實現(xiàn)圖片預(yù)覽

image.png
2.9.1 實現(xiàn)圖片預(yù)覽
post-comment.wxml
          <view class='comment-img' wx:if="{{item.content.img.length!=0}}">
          <block wx:for="{{item.content.img}}" wx:for-item="img" wx:for-index="imgIdx">
          <image src='{{img}}' mode='aspectFill' catchtap='previewimg' data-comment-idx='{{idx}}' data-img-idx='{{imgIdx}}'></image>
          </block>
          </view>
image.png
image.png
image.png

2.10 實現(xiàn)提交評論的界面

2.10.1 評論框的骨架
post-comment.wxml
 <view class="input-box">
    <view class="send-msg-box">
      <view hidden="{{useKeyboardFlag}}" class="input-item">
        <image src="/images/icon/wx_app_keyboard.png" class="comment-icon keyboard-icon" catchtap="switchInputType"></image>
        <input class="input speak-input {{recodingClass}}" value="按住 說話" disabled="disabled" catchtouchstart="recordStart" catchtouchend="recordEnd" />
      </view>
      <view hidden="{{!useKeyboardFlag}}" class="input-item">
        <image class="comment-icon speak-icon" src="/images/icon/wx_app_speak.png" catchtap="switchInputType"></image>
        <input class="input keyboard-input"  value="{{keyboardInputValue}}" bindconfirm="submitComment" bindinput="bindCommentInput" placeholder="說點什么吧……" />
      </view>
      <image class="comment-icon add-icon" src="/images/icon/wx_app_add.png" catchtap="sendMoreMsg"></image>
      <view class="submit-btn" catchtap="submitComment">發(fā)送</view>
    </view>
 </view>
2.10.2 評論框的樣式
post-comment.wxss

/*******************評論框**********************/
.input-box{
    position: absolute;
    bottom: 0;
    left:0;
    right: 0;
    background-color: #EAE8E8;
    border-top:1rpx solid #D5D5D5;
    min-height: 100rpx;
    z-index: 1000;
}
.input-box .send-msg-box{
    width: 100%;
    height: 100%;
    display: flex;
    padding: 20rpx 0;
}
.input-box .send-more-box{
    margin: 20rpx 35rpx 35rpx 35rpx;
}
.input-box .input-item{
    margin:0 5rpx;
    flex:1;
    width: 0%;
    position: relative;
}
.input-box .input-item .comment-icon{
    position: absolute;
    left:5rpx;
    top:6rpx;
}

.input-box .input-item .input{
    border: 1rpx solid #D5D5D5;
    background-color: #fff;
    border-radius: 3px;
    line-height: 65rpx;
    margin:5rpx 0 5rpx 75rpx ;
    font-size: 24rpx;
    color: #838383;
    padding: 0 2%;
}
.input-box .input-item .keyboard-input{
    width: auto;
    max-height: 500rpx;
    height: 65rpx;
    word-break:break-all;
    overflow:auto;
}
.input-box .input-item .speak-input{
    text-align: center;
    color: #212121;
    height: 65rpx;
}

.input-box .input-item .recoding{
    background-color: #ccc;
}

.input-box .input-item .comment-icon.speak-icon{
    height: 62rpx;
    width: 62rpx;
}
.input-box .input-item .comment-icon.keyboard-icon{
    height: 60rpx;
    width: 60rpx;
    left:6rpx;
}
.input-box .add-icon{
    margin:0 5rpx;
    height: 65rpx;
    width: 65rpx;
    transform: scale(0.9);
    margin-top: 2px;
}
.input-box .submit-btn{
    font-size: 24rpx;
    margin-top: 5rpx;
    margin-right: 8rpx;
    line-height: 60rpx;
    width: 120rpx;
    height: 60rpx;
    background-color: #4A6141;
    border-radius:5rpx;
    color: #fff;
    text-align: center;
    font-family:Microsoft Yahei;
}


.send-more-box .more-btn-item{
    display: inline-block;
    width: 110rpx;
    height: 145rpx;
    margin-right: 35rpx;
    text-align: center;
}

.more-btn-main{
    width: 100%;
    height:60rpx;
    text-align: center;
    border:1px solid #D5D5D5;
    border-radius: 10rpx;
    background-color: #fbfbfc;
    margin: 0 auto;
    padding:25rpx 0
}
.more-btn-main image{
    width: 60rpx;
    height: 60rpx;
}
.send-more-box .more-btn-item .btn-txt{
    color: #888888;
    font-size: 24rpx;
    margin:10rpx 0;
}

.send-more-result-main{
    margin-top: 30rpx;
}
.send-more-result-main .file-box{
    margin-right: 14rpx;
    height: 160rpx;
    width: 160rpx;
    position: relative;
    display: inline-block;
}

.send-more-result-main .file-box.deleting{
    animation:deleting 0.5s ease;
    animation-fill-mode: forwards;
}

@keyframes deleting {
    0%{
        transform: scale(1);
    }
    100%{
        transform: scale(0);
    }
}

.send-more-result-main image{
    height: 100%;
    width: 100%;
}
.send-more-result-main .remove-icon{
    position: absolute;
    right: 5rpx;
    top: 5rpx;
}

.send-more-result-main .file-box .img-box {
    height: 100%;
    width: 100%;
image.png

2.11 wx:if 與 hidden控制元素顯示和隱藏

在小程序中,隱藏UI元素的方法有倆種:
1)wx:if
2)hidden


image.png

它們都是通過一個狀態(tài)變量來控制元素的顯示和隱藏

  • wx:if 和 hidden 有什么異同?
    1)wx:if的切換和渲染機制較為復(fù)雜,當(dāng)wx:if進行切換時,MINA框架有一個局部渲染的過程,它會確保條件塊在切換時銷毀或者重新渲染。
    2)wx:if是惰性的,如果初始渲染條件為false,那么MINA框架什么也不做,在條件第一次變成真的時候才開始局部渲染。
    3)hidden就比較簡單,組件始終會被渲染,只是簡單地控制顯示與隱藏
    4)一般來說,wx:if有更高的切換消耗,而hidden有更高的初始化渲染消耗。因此,在需要頻繁切換的情境下用hidden更好,在運行時條件不太可能改變時用wx:if較好。

2.12 實現(xiàn)文字評論框和語音評論框的切換

2.12.1 初始化useKeyboardFlag
post-comment.js
image.png
2.12.1 切換useKeyboardFlag
post-comment.js
image.png
image.png
image.png

2.13 input組件

屬于小程序中最為重要的數(shù)據(jù)輸入組件

2.13.1 屬性介紹
image.png

image.png
2.13.2 事件介紹
image.png

由MINA框架直接指定的,屬于非冒泡事件,不需要在事件名稱前面再添加catch和bind

  • bindinput事件較為特殊,具有如下幾個特點:
    1)當(dāng)用戶輸入字符時觸發(fā)
    2)每當(dāng)用戶輸入或者刪除一個字符時,bindinput事件都會觸發(fā)一次
    3)可以在事件響應(yīng)函數(shù)中使用return返回一個字符或者字符串,該字符串將替換input輸入框的顯示文本
    4)比較適合用來做“即時搜索”的功能

input輸入值都是在事件對應(yīng)的響應(yīng)函數(shù)中使用 event.detail.value來獲取

2.14 bindinput事件

2.14.1 響應(yīng)bindinput事件
post-comment.js
  //獲取用戶輸入
  bindCommentInput:function(event){
    var val = event.detail.value;
    console.log(val);
    this.data.keyboardInputValue = val;
  }
image.png

2.15 屏蔽評論關(guān)鍵字

bindinput還有一個有意思的特性,就是在事件響應(yīng)函數(shù)中可以return一個值來代替當(dāng)前的輸入值,并顯示在input中

2.15.1 bindinput的return值
post-comment.js

將這個函數(shù)的代碼臨時改一下,用來測試

    bindCommentInput: function (event) {
    var val = event.detail.value;
    return val + "#";
image.png
2.15.2 屏蔽關(guān)鍵字“qq”
post-comment.js
 bindCommentInput: function(event) {
    var value = event.detail.value;
    var pos = event.detail.cursor;
    console.log("pos======" + pos);
    if (pos != -1) {
      //光標在中間
      var left = event.detail.value.slice(0, pos);
      console.log(left);
      //計算光標的位置
      pos = left.replace(/qq/g, "*").length;
    }
    //直接返回對象,可以對輸入進行過濾處理,同時可以控制光標的位置
    return {
      value: value.replace(/qq/g, "*"),
      cursor: pos
    };
  }
image.png
2.15.3 簡化版屏蔽關(guān)鍵字“qq”
post-comment.js
 bindCommentInput: function(event) {
    var value = event.detail.value;
    return value.replace(/qq/g, "*");
  }

image.png

2.16 實現(xiàn)自定義發(fā)送按鈕

2.16.1 實現(xiàn) submitComment 方法
post-comment.js
//提交用戶評論
  submitComment: function(event) {
    var newData = {
      username: "青石",
      avatar: "/images/avatar/avatar-3.png",
      //評論時間
      create_time: new Date().getTime() / 1000,
      //評論內(nèi)容
      content: {
        text: this.data.keyboardInputValue
      },
    };

    if (!newData.content.text) {
      //如果沒有評論內(nèi)容,就不執(zhí)行任何操作
      return;
    }

    //保存新評論到緩存數(shù)據(jù)庫中
    this.dbPost.newComment(newData);
    //顯示操作結(jié)果
    this.showCommitSuccessToast();
    //重新渲染并綁定所有評論
    this.bindCommentData();
    //恢復(fù)初始狀態(tài)
    this.resetAllDefaultStatus();
  },
2.16.2 編寫newComment方法
DBPost.js
 //發(fā)表評論
  newComment(newComment) {
    this.updatePostData("comment", newComment);
  }

2.16.3 在updatePostData中處理新評論
DBPost.js
 //更新本地的點贊、評論信息、收藏、閱讀量
  updatePostData(category, newComment) {
    var itemData = this.getPostItemById(),
      postData = itemData.data,
      allPostData = this.getAllPostData();

    switch (category) {
      case 'collect':
        //處理收藏
        if (!postData.collectionStatus) {
          //如果當(dāng)前狀態(tài)是未收藏
          postData.collectionNum++;
          postData.collectionStatus = true;
        } else {
          //如果當(dāng)前狀態(tài)是收藏
          postData.collectionNum--;
          postData.collectionStatus = false;
        }
        break;
      case 'up':
        if (!postData.upStatus) {
          postData.upNum++;
          postData.upStatus = true;
        } else {
          postData.upNum--;
          postData.upStatus = false;
        }
        break;

      case "comment":
        postData.comments.push(newComment);
        postData.commentNum++;
        break;
      default:
        break;
    }
2.16.4 編寫新增評論成功的提示方法
post-comment.js
  //評論成功
  showCommitSuccessToast: function() {
    wx.showToast({
      title: '評論成功',
      duration: 1000,
      icon: "success"
    })
  },
2.16.5 重新綁定評論數(shù)據(jù)
post-comment.js
bindCommentData: function() {
    var comments = this.dbPost.getCommentData();
    //綁定評論數(shù)據(jù)
    this.setData({
      comments: comments
    })
  },
2.16.6 重置input組件的輸入值
post-comment.js
  //將所有相關(guān)的按鈕狀態(tài)、輸入狀態(tài)都回復(fù)到初始化狀態(tài)
  resetAllDefaultStatus: function() {
    //清空評論框
    this.setData({
      keyboardInputValue: ""
    })
  }
image.png

2.17 同時支持模擬器回車、真機點擊“完成”發(fā)送評論

如果要想在模擬器中實現(xiàn)回車發(fā)送評論信息的功能,可以使用如下幾個input事件:

  • bindchange(早期版本存在,新版本說明文檔不在了,不過依然有效,只是不建議用)
  • bindblur:可以觸發(fā)回車的原理是:點擊回車后,input組件將失去焦點,從而觸發(fā)bindblur事件
  • bindconfirm:可以在真機上響應(yīng)鍵盤的“完成”點擊事件,同時也可以在模擬器中響應(yīng)鍵盤的“回車”事件
2.17.1 添加bindcomfirm事件
post-comment.wxml
image.png

2.18 圖片與拍照評論的界面實現(xiàn)

2.18.1 選擇圖片與拍照面板代碼
post-comment.wxml
    <view class="send-msg-box">
      <view hidden="{{useKeyboardFlag}}" class="input-item">
        <image src="/images/icon/wx_app_keyboard.png" class="comment-icon keyboard-icon" catchtap="switchInputType"></image>
        <input class="input speak-input {{recodingClass}}" value="按住 說話" disabled="disabled" catchtouchstart="recordStart" catchtouchend="recordEnd" />
      </view>
      <view hidden="{{!useKeyboardFlag}}" class="input-item">
        <image class="comment-icon speak-icon" src="/images/icon/wx_app_speak.png" catchtap="switchInputType"></image>
        <input class="input keyboard-input"  value="{{keyboardInputValue}}" bindconfirm="submitComment" bindinput="bindCommentInput" placeholder="說點什么吧……" />
      </view>
      <image class="comment-icon add-icon" src="/images/icon/wx_app_add.png" catchtap="sendMoreMsg"></image>
      <view class="submit-btn" catchtap="submitComment">發(fā)送</view>
    </view>

     <view class="send-more-box" hidden="{{!sendMoreMsgFlag}}">

      <!--選擇圖片和拍照的按鈕-->
      <view class="send-more-btns-main">
        <view class="more-btn-item" catchtap="chooseImage" data-category="album">
          <view class="more-btn-main">
            <image src="/images/icon/wx_app_upload_image.png"></image>
          </view>
          <text>照片</text>
        </view>
        <view class="more-btn-item" catchtap="chooseImage" data-category="camera">
          <view class="more-btn-main">
            <image src="/images/icon/wx_app_camera.png"></image>
          </view>
          <text>拍照</text>
        </view>
      </view>

      <!--顯示選擇的圖片-->
      <view class="send-more-result-main" hidden="{{chooseFiles.length==0}}">
        <block wx:for="{{chooseFiles}}" wx:for-index="idx">

          <!--如果刪除其中一個,則對其添加deleting 樣式;-->
          <view class="file-box {{deleteIndex==idx?'deleting':''}}">
            <view class="img-box">
              <image src="{{item}}" mode="aspectFill"></image>
              <icon class="remove-icon" type="cancel" size="23" color="#B2B2B2" catchtap="deleteImage" data-idx="{{idx}}" />
            </view>
          </view>
        </block>
      </view>
    </view>
 </view>
</view>

2.18.2 編寫sendMoreMsg方法
image.png
post-comment.js
image.png
sendMoreMsg:function(){
    this.setData({
      sendMoreMsgFlag: !this.data.sendMoreMsgFlag
    })
  }
image.png

2.19 實現(xiàn)從相冊選擇照片與拍照

2.19.1 新增chooseFiles變量
post-comment.js
  /**
   * 頁面的初始數(shù)據(jù)
   */
  data: {
    //控制使用鍵盤還是發(fā)送語音
    useKeyboardFlag: true,
    //控制input組件的初始值
    keyboardInputValue:"",
    //控制是否顯示圖片選擇面板
    sendMoreMsgFlag:false,
    //保存已經(jīng)選擇的圖片
    chooseFiles:[]
  },
2.19.2 實現(xiàn)選擇圖片與拍照功能
post-comment.js
//選擇本地照片與拍照
  chooseImage: function(event) {
    //已選擇圖片數(shù)組
    var imgArr = this.data.chooseFiles;
    //只能上傳3張照片,包括拍照
    var leftCount = 3 - imgArr.length;
    if (leftCount <= 0) {
      return;
    }
    var sourceType = [event.currentTarget.dataset.category],
      that = this;
    console.log("sourceType==============" + sourceType);
    console.log("that==============" + that);
    wx.chooseImage({
      count: leftCount,
      sourceType: sourceType,
      success: function(res) {
        that.setData({
          chooseFiles: imgArr.concat(res.tempFilePaths)
        })
      },
    })
  }
image.png
image.png

注意,sourceType的傳值過程

image.png

2.20 icon圖片

image.png

image.png

2.21 刪除已選擇的圖片

2.21.1 deleteImage方法
post-comment.js
  //刪除已經(jīng)選擇的圖片
  deleteImage: function(event) {
    var index = event.currentTarget.dataset.idx;
    var that = this;
    that.data.chooseFiles.splice(index, 1);
    that.setData({
      chooseFiles: that.data.chooseFiles
    })
  }

獲取當(dāng)前刪除圖片的序號,并且將該圖片的URL從 this.data.chooseFiles數(shù)組中刪除,重新綁定chooseFiles變量即可

2.22 在小程序中使用CSS 3動畫

image.png

如果delete的值等于當(dāng)前圖片的序號,就說明該圖片是要被刪除的,需要添加一個deleteing動畫


image.png
2.22.1 修改deleteImage方法
post-comment.js
image.png
 //刪除已經(jīng)選擇的圖片
  deleteImage: function(event) {
    var index = event.currentTarget.dataset.idx;
    var that = this;
    that.setData({
      deleteIndex:index
    });
    that.data.chooseFiles.splice(index, 1);
    setTimeout(function(){
      that.setData({
        deleteIndex:-1,
        chooseFiles: that.data.chooseFiles
      })
    },1000)
  }
image.png

2.23 實現(xiàn)圖片評論的發(fā)送

實現(xiàn)原理:把當(dāng)前的this.data.chooseFiles所保存的圖片地址存入數(shù)據(jù)庫緩存中,并且重新渲染評論列表即可。

修改如下的方法

2.23.1 修改submitComment方法
post-comment.js
//提交用戶評論
  submitComment: function(event) {
    var imgs = this.data.chooseFiles;
    var newData = {
      username: "青石",
      avatar: "/images/avatar/avatar-3.png",
      //評論時間
      create_time: new Date().getTime() / 1000,
      //評論內(nèi)容
      content: {
        text: this.data.keyboardInputValue,
        img:imgs
      },
    };

    if (!newData.content.text && imgs.length == 0) {
      //如果沒有評論內(nèi)容,就不執(zhí)行任何操作
      return;
    }

    //保存新評論到緩存數(shù)據(jù)庫中
    this.dbPost.newComment(newData);
    //顯示操作結(jié)果
    this.showCommitSuccessToast();
    //重新渲染并綁定所有評論
    this.bindCommentData();
    //恢復(fù)初始狀態(tài)
    this.resetAllDefaultStatus();
  },
2.23.2 修改submitComment方法
post-comment.js
  //將所有相關(guān)的按鈕狀態(tài)、輸入狀態(tài)都回復(fù)到初始化狀態(tài)
  resetAllDefaultStatus: function() {
    //清空評論框
    this.setData({
      keyboardInputValue: "",
      chooseFiles:[],
      sendMoreMsgFlag:false
    })
  },
image.png

2.24 實現(xiàn)語音信息的發(fā)送

  • 發(fā)送語音評論的操作過程:
    1)切換到語音面板
    2)長按“按住說話”這個按鈕
    3)說話
    4)松開“按住說話”,語音信息自動發(fā)送

[圖片上傳中...(image.png-a8f196-1529334605160-0)]

2.24.1 實現(xiàn)recodrdStart
post-comment.js
//開始錄音
  recordStart: function() {
    var that = this;
    this.setData({
      recodingClass: "recoding"
    });
    //記錄錄音開始時間
    this.startTime = new Date();
    console.log("this.startTime============" + this.startTime);
    wx.startRecord({
      success: function(res) {
        //計算錄音時長
        var diff = (that.endTime - that.startTime) / 1000;
        console.log("diff============" + diff);
        diff = Math.ceil(diff);
        console.log("diff======ceil======" + diff);

        //發(fā)送錄音
        that.submitVoiceComment({
          url: res.tempFilePath,
          timeLen: diff
        });
      },

      fail: function(res) {
        console.log("fail============" + res);
      },
      complete: function(res) {
        console.log("complete============" + res);
      }
    })
  },
2.24.2 結(jié)束錄音
post-comment.js
 //結(jié)束錄音
  recordEnd: function() {
    this.setData({
      recodingClass: ""
    });
    this.endTime = new Date();
    wx.stopRecord();
  },
2.24.3 發(fā)送語音評論
post-comment.js
//提交錄音
  submitVoiceComment: function (audio){
    var newData = {
      username: "青石",
      avatar: "/images/avatar/avatar-3.png",
      //評論時間
      create_time: new Date().getTime() / 1000,
      //評論內(nèi)容
      content: {
        text: "",
        img: [],
        audio:audio
      },
    };
    console.log("submitVoiceComment====create_time=========" + newData.create_time);

    //保存新評論到緩存數(shù)據(jù)中
    this.dbPost.newComment(newData);

    //顯示操作結(jié)果
    this.showCommitSuccessToast();

    //重新渲染并且綁定所有評論
    this.bindCommentData();
  }
image.png
image.png

2.25 實現(xiàn)語音信息的暫停與播放

語音評論的播放需要滿足以下幾個播放場景。假設(shè)有兩個信息------A語音和B語音,當(dāng)點擊A語音時:

  • 如果A語音處于未播狀態(tài),就開始播放A語音
  • 如果A語音處于暫停狀態(tài),就繼續(xù)播放A語音
    當(dāng)點擊B語音時:
  • B語音的行為同上述A語音
  • 無論A語音處于何種狀態(tài),都將立刻被中斷;被中斷后,再次點擊A語音,A語音重新開始播放
2.25.1 發(fā)送語音評論
post-comment.js
playAudio: function(event) {
    console.log("playAudio=============");
    var url = event.currentTarget.dataset.url,
      that = this;
    console.log("url=============" + url);
    //暫停當(dāng)前錄音
    if (url == this.data.currentAudio) {
      wx.pauseVoice();
      this.data.currentAudio = ""

      //播放錄音
    } else {
      this.data.currentAudio = url;
      wx.playVoice({
        filePath: url,
        complete: function() {
          //只有當(dāng)錄音播放完畢后才會執(zhí)行
          that.data.currentAudio = ""
        }
      })
    }
  }
2.25.2 定義currentAudio變量
post-comment.js
  data: {
    //控制使用鍵盤還是發(fā)送語音
    useKeyboardFlag: true,
    //控制input組件的初始值
    keyboardInputValue: "",
    //控制是否顯示圖片選擇面板
    sendMoreMsgFlag: false,
    //保存已經(jīng)選擇的圖片
    chooseFiles: [],
    //被刪除的圖片序號
    deleteIndex: -1,
    //保存當(dāng)前正在播放語音的URL
    currentAudio: ''
  },
image.png

2.26 用戶授權(quán)

使用某些特定的API,是需要用戶主動授權(quán)的,比如,調(diào)用wx.startRecord接口錄音時,需要用戶主動授權(quán),如下所示:


image.png

如果用戶點擊確定后,以后使用該功能的時候都不會提示,如果要讓彈出授權(quán)框,需要手動清除授權(quán)文件,如下所示:


image.png

2.27 解決真機運行時評論頁面滑動卡頓的問題

image.png

2.28 文章閱讀計算功能

2.28.1 閱讀數(shù)+1
post-detail.js
//閱讀量+1
  addReadingTimes:function(){
    this.dbPost.addReadingTimes();
  }
2.28.2 閱讀數(shù)+1的緩存操作方法
DBPost.js
  //閱讀量+1
  addReadingTimes() {
    this.updatePostData("reading");
  }
2.28.3 updatePostData方法最終代碼
DBPost.js
 //更新本地的點贊、評論信息、收藏、閱讀量
  updatePostData(category, newComment) {
    var itemData = this.getPostItemById(),
      postData = itemData.data,
      allPostData = this.getAllPostData();

    switch (category) {
      case 'collect':
        //處理收藏
        if (!postData.collectionStatus) {
          //如果當(dāng)前狀態(tài)是未收藏
          postData.collectionNum++;
          postData.collectionStatus = true;
        } else {
          //如果當(dāng)前狀態(tài)是收藏
          postData.collectionNum--;
          postData.collectionStatus = false;
        }
        break;
      case 'up':
        if (!postData.upStatus) {
          postData.upNum++;
          postData.upStatus = true;
        } else {
          postData.upNum--;
          postData.upStatus = false;
        }
        break;

      case "comment":
        postData.comments.push(newComment);
        postData.commentNum++;
        break;

      case "reading":
        postData.readingNum++;
        break;
      default:
        break;
    }
2.28.4 調(diào)用addReadingTimes方法
post-detail.js
  /**
   * 生命周期函數(shù)--監(jiān)聽頁面加載
   */
  onLoad: function (options) {
    var postId = options.id;
    this.dbPost = new DBPost(postId);
    this.postData = this.dbPost.getPostItemById().data;
    this.setData({
      post:this.postData
    })

    this.addReadingTimes();
  },

每次進來閱讀量都會加1


image.png
image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容