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);
}

- 屬性注意點
1)transform: scale()屬性


2)display: inline-block;屬性


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>

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)的問題,目前主要有如下幾個:

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


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>

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

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')

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;
}

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

2).comment-item:last-child

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

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>



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%;

2.11 wx:if 與 hidden控制元素顯示和隱藏
在小程序中,隱藏UI元素的方法有倆種:
1)wx:if
2)hidden

它們都是通過一個狀態(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

2.12.1 切換useKeyboardFlag
post-comment.js



2.13 input組件
屬于小程序中最為重要的數(shù)據(jù)輸入組件
2.13.1 屬性介紹


2.13.2 事件介紹

由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;
}

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 + "#";

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
};
}

2.15.3 簡化版屏蔽關(guān)鍵字“qq”
post-comment.js
bindCommentInput: function(event) {
var value = event.detail.value;
return value.replace(/qq/g, "*");
}

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: ""
})
}

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

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方法

post-comment.js

sendMoreMsg:function(){
this.setData({
sendMoreMsgFlag: !this.data.sendMoreMsgFlag
})
}

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)
})
},
})
}


注意,sourceType的傳值過程

2.20 icon圖片


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動畫

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

2.22.1 修改deleteImage方法
post-comment.js

//刪除已經(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)
}

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
})
},

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();
}


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: ''
},

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

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

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

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


