[打怪升级]小程序评论回复和发贴功能实战(一)

image

在学习成长的过程当中,经常会遇到一些本身从未接触的事物,这就比如是打怪升级,每次打倒一只怪,都会得到经验,让本身进步强大。特别是咱们这些作技术的,逆水行舟不进则退。下面分享下小程序开发中的打怪升级经历~html

效果图

先来看下实际效果图,小程序开发中有时会要作一些的功能复杂的组件,好比评论回复和发帖功能等,此次主要讲的是关于评论模块的一些思路和实战中的经验,但愿能抛砖引玉,给你们一些启发,一同成长~前端

>>(最下面有实战demo的地址,能够直接浏览器打开添加至IDE工具中) <<node

评论组件流程图

根据这个demo.gif,本人作了一个简单的流程图,帮助你们理解。下面罗列一些开发中须要“打的怪”:react

一、组件目录结构

├─components      ---小程序自定义组件
│  ├─plugins      --- (重点)可独立运行的大型模块,能够打包成plugins
│  │  ├─comment         ---评论模块
│  │  │  │  index.js
│  │  │  │  index.json
│  │  │  │  index.wxml
│  │  │  │  index.wxss
│  │  │  │  services.js    ---(重点)用来处理和清洗数据的service.js,配套模板和插件
         │      
         └─submit    ---评论模块子模块:提交评论
                 index.js
                 index.json
                 index.wxml
                 index.wxss

复制代码

为何要单独作个评论页面页面(submit)? 由于若是是当前页面最下面input输入的形式,会出现一些兼容问题,好比:json

  • 不一样手机的虚拟键盘高度不一样,很差绝对定位和彻底适配
  • 弹窗输入框太小输入不方便,若是是大的textare时,容易误触下面评论的交。

注:目录结构,仅供参考。小程序

二、NODE端API接口返回结构和页面结构

//node:API接口返回
{
    "data": {
        "commentTotal": 40,
        "comments": [
            {
                "contentText": "喜欢就关注我",   //评论内容
                "createTime": 1560158823647,    //评论时间
                "displayName": "智酷方程式",       //用户名
                "headPortrait": "https://blz.nosdn.127.net/1/weixin/zxts.jpg",  //用户头像
                "id": "46e0fb0066666666",  //评论ID  用于回复和举报
                "likeTotal": 2,    //点赞数
                "replyContents": [   //回复评论
                    {
                        "contentText": "@智酷方程式 喜欢就回复我",   //回复评论内容
                        "createTime": 1560158986524,   //回复时间
                        "displayName": "神秘的前端开发",   //回复的用户名
                        "headPortrait": "https://blz.nosdn.127.net/1/2018cosplay/fourth/tesss.jpg",  //回复的用户头像
                        "id": "46e0fb00111111111",   //回复评论的ID
                        "likeTotal": 2,    //回复评论的点赞数
                        "replyContents": [],   //回复的回复 盖楼
                        "replyId": "46e0fb001ec222222222",   //回复评论的独立ID,用于统计
                    },
                    {
                        "contentText": "@智酷方程式: 威武,学习学习",
                        "createTime": 1560407232814,
                        "displayName": "神秘的前端开发",
                        "headPortrait": "https://blz.nosdn.127.net/1/2018cosplay/fourth/tesss.jpg",
                        "id": "46e0fb00111111111",
                        "likeTotal": 0,
                        "replyContents": [],
                        "replyId": "46e0fb001ec222222222",
                    }
                ],
                "replyId": "",
                "topicId": "46e0fb001ec3333333",
            }
        ],
        "curPage": 1,  //当前页面
        //经过ID 判断  当前用户点赞了 哪些评论
        "likes": [
            "46e0fb00111111111",    
            "46e0fb001ec222222222",
            "46e0fb0066666666",
        ],
        "nextPage": null, //下一页
        "pageSize": 20,  //一页总共多少评论
        "total": 7,   //总共多少页面
    },
    "msg": "success",
    "status": "success"
}
复制代码
<!-- HTML 部分 -->
<block wx:if="{{commentList.length>0}}">
    <!-- 评论模块 -->
    <block wx:for="{{commentList}}" wx:for-item="item" wx:for-index="index" wx:key="idx">
        <view class="commentItem" catchtap="_goToReply" data-contentid="{{item.id}}" data-replyid="{{item.id}}"
            data-battle-tag="{{item.displayName}}">
            <view class="titleWrap">
                <image class="logo" src="{{item.headPortrait||'默认图'}}"></image>
                <view class="authorWrap">
                    <view class="author">{{item.displayName}}</view>
                    <view class="time">{{item.createTime}}</view>
                </view>
                <view class="starWrap" catchtap="_clickLike" data-index="{{index}}" data-like="{{item.like}}"
                    data-contentid="{{item.id}}" data-topicid="{{item.topicId}}">
                    <text class="count">{{item.likeTotal||""}}</text>
                    <view class="workSprite icon {{item.like?'starIconHasClick':'starIcon'}}"></view>
                </view>
            </view>
            <view class="text">
                {{item.contentText}}
            </view>
        </view>
        <!-- 评论的评论 -->
        <block wx:for="{{item.replyContents}}" wx:for-item="itemReply" wx:for-index="indexReply" wx:key="idxReply">
            <view class="commentItem commentItemReply" catchtap="_goToReply" data-contentid="{{itemReply.id}}"
                data-replyid="{{item.id}}" data-battle-tag="{{itemReply.displayName}}">
                ... 和上面相似
            </view>
        </block>
    </block>
    <!-- 加载更多loading -->
    <block wx:if="{{isOver}}">
        <view class="more">评论加载完成</view>
    </block>
</block>
复制代码

经过node提供一个API接口,经过用户的openId来判断是否点赞,这里提供一个参考的JSON结构。 JSON尽可能作成array循环的结构方便渲染,根据ID来BAN人和管理。底部加上加载更多的效果,同时,记得作一些兼容,好比默认头像等。数组

三、评论中的一些微信原生交互

这里建议不少交互若是不是必需要特别定制,能够才用微信原生的组件,效果和兼容性都有保障,并且方便简单。浏览器

对评论进行回复/举报

<!-- HTML部分 经过绑定事件:_goToReply 进行交互-->
<view class="commentItem" catchtap="_goToReply" data-contentid="{{item.id}}" data-replyid="{{item.id}}"
    data-battle-tag="{{item.displayName}}">
    ... 内部省略
</view>
复制代码
//JS部分  微信原生wx.showActionSheet 显示操做菜单交互
_goToReply(e) {
    //  上面的各类受权判断省略...
    let self = this;
    wx.showActionSheet({
        itemList: ['回复', '举报'],
        success: function (res) {
            if (!res.cancel) {
                console.log(res.tapIndex);
                //前往评论
                if (res.tapIndex == 0) {
                    //判断是不是 评论的评论
                    self._goToComment(replyid);
                }
                //举报按钮
                if (res.tapIndex == 1) {
                    //弹出框
                    self.setComplain(contentid);
                }
            } else { //取消选择
                
            }
        },
        fail(res) {
            console.log(res.errMsg)
        }
    });
}
//当选择“举报”的时候,二次调用 wx.showActionSheet 方法
setComplain(contentid){
    let complainJson = ["敏感信息", "色情淫秽", "垃圾广告", "语言辱骂", "其它"];
    wx.showActionSheet({
        itemList: complainJson,
        success: async res => {
            if (!res.cancel) {
                //选择好后,提交举报
                try {
                    let complainResult = await request.postComplainReport(complainJson[index], openid, contentid);
                    if (complainResult.msg == "success") {  //提交成功后反馈

                    } else {

                    }
                } catch (e) {
                    console.log(e)
                }
            }
        }
    });
}
复制代码

显示操做菜单 wx.showActionSheet 方法说明bash

属性 类型 说明
itemList Array. 按钮的文字数组,数组长度最大为 6
itemColor string 按钮的文字颜色
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

使用这个方法,便是主流的作法,也能很好的兼容不一样机型,同时给予用户“习惯性体验”。微信

原生评论排序切换

评论排序切换示例

<!-- picker组件  html部分-->
<picker bindchange="bindPickerChange" value="{{index}}" range="{{array}}">
    <view class="picker">
        当前选择:{{array[index]}}
    </view>
</picker>
复制代码
// js部分
Page({
    data:{
        //查看评论类型切换
        array: ["最佳", "最新", "只看本身"],
        //选择数组中的第几个显示
        index:0
    },
    bindPickerChange(e) {
        console.log('picker发送选择改变,携带值为', e.detail.value)
        this.setData({
            index: e.detail.value
        })
    }
})
复制代码

picker组件是一个从底部弹起的滚动选择器,这里咱们用它来切换不一样评论的排序。每次切换均可以经过 bindchange得到对应的变化,经过 e.detail.value获取用户选择的索引值。
官方文档:
developers.weixin.qq.com/miniprogram…

四、传参跳转写评论页

let uriData = {
    logo: "xxx.jpg",
    type: "commentReply",
    title: "文章:小程序评论,动态发帖开发指北\n 做者:智酷方程式",
    openId:"xxxxxxxxxxx",
    replyId:"aaaaaa"   //用户回复的是哪一个评论的ID
};
wx.navigateTo({ url: `/components/plugins/comment/submit/index?uriData=${encodeURIComponent(JSON.stringify(uriData))}` });
复制代码

这个能够用encodeURIComponent的方式处理下参数中的中文,避免跳转发布评论页接收数据时出现乱码。

五、发表评论页

发表评论页

显示和控制评论的字数

<!-- html部分  关于textarea 的配置 -->
<view class='feedback-cont'>
    <textarea auto-focus="true" value="{{replyName}}" maxlength="200" bindinput="textareaCtrl"
        placeholder-style="color:#999;" placeholder="留下评论,共同窗习,一块儿进步" />
    <view class='fontNum'>{{content.length}}/200</view>
</view>
<view class='feedback-btn' bindtap='commentSubmit'>提交</view>
复制代码
// js部分
Page({
    data: {
        //初始化评论内容,若是是回复则经过传参变成 @xxxx的形式
        content: "@xxxx",
    },
    textareaCtrl: function (e) {
        if (e.detail.value) {
            this.setData({
                content: e.detail.value
            })
        } else {
            this.setData({
                content: ""
            })
        }
    }
})
复制代码

textarea 在小程序中改动不大,这个标签原有的一些属性均可以继续使用,经过配置maxlength来控制字数,同时,设置auto-focus="true"可让用户进到这个发表评论页面时自动弹出虚拟键盘和光标定位在输入的区域。

固然,也能够将发表评论评论展现区域作在一块儿,这个就要考虑到要么经过“小程序API”获取键盘高度,要么将“发布评论”置顶区域显示,也是能够作的,只是相对考虑的点会多些。当时开发评论组件的时候,考虑开发时间短和用户体验,权衡后,最终决定以上方案,但愿能给到你们一些参考和借鉴,在其余组件开发中举一反三。

[代码片断]评论回复组件实战demo

demo的微信路径:developers.weixin.qq.com/s/oHs5cMma7…

demo的ID:oHs5cMma7N9W

若是你装了IDE工具,能够直接访问上面的demo路径

经过代码片断将demo的ID输入进去也可添加:

浏览器打开路径
打开代码片断

总结,“组件化思想”对于不管作小程序、react/VUE仍是其余项目来讲,减小重复开发,提升复用性都是一个很是重要的点。评论功能其实只要理清楚总体思路,作起来难度并不大,经过一些原生组件,能够大大提升开发效率,同时保证良好的兼容性。 后面一期还将分享下功能点较多的发帖组件开发。

往期回顾:
[填坑手册]小程序Canvas生成海报(一)
[拆弹时刻]小程序Canvas生成海报(二)
[填坑手册]小程序目录结构和component组件使用心得

相关文章
相关标签/搜索