微信小程序的用户评论功能

目录

一、工具

二、实现

1.数据存储准备

2.用户头像和昵称等信息的保存

3.获取并保存用户输入的内容(保存input的内容)

4.评论的显示

但是还没结束

5.功能完善,实现分页

6.自己发的自己可以删除

三、总结

 首先,你有更好的方法,那一定是你的方法更好,我赞同。

 一、工具

1.微信开发者工具

2.微信云开发能力

二、实现

以我的小程序项目--南苑口袋中的食堂评论功能为例(以下简称为口袋),欢迎大家参观哟~

1.数据存储准备

1.1在云开发中的云数据库创建一个集合用来存储评论(我命名为“comment”)

1.2先自己确定集合中的每条记录需要的属性是什么

以我为例:

①口袋中每个店铺都需要有针对的评论,所以我需要一个标识食堂的属性“foodId”;

②最基本的我要区分谁发的,用户的openid;

③我要显示发送评论的用户的信息,头像“avatarUrl(头像链接)”,昵称“nickName”;

④最重要的评论内容“comment”

7d6f05bc90424e5aad50b90f0df4e6e3.png

2.用户头像和昵称等信息的保存

在评论显示前,我就要有用户的头像显示,如下

5bb89f8c9ce54b20a18b8a297adb5f3c.png

所以我将头像链接以及用户昵称以对象形式保存在data: { }中,方便渲染。

至于头像和昵称的获取,看自己的项目要求,我是在个人信息页面使用了微信开放能力中的“头像昵称填写”来获取和保存的;

如何把这些数据传到到带评论的这个页面也看你们自己,是用本地存储还是globalData还是直接数据库获取或者其他方法都可以随便你。

3.获取并保存用户输入的内容(保存input的内容)

假设你用的input标签

3.1获取input标签的输入内容

这个没什么好说的,就是代码,微信开放文档一看就懂(标签自带input事件,js参数获取)

<input placeholder="说点什么..." type="text" bindinput="comment" />
//js代码
comment: function (e) {
    // console.log(e.detail.value)
    comment = e.detail.value
},

这里comment我用全局变量保存下来。

3.2评论提交按钮提交事件(保存下来)

①这里口袋会先判断用户登录状态(也是看自己项目之前是怎么判断用户登录状态的,直接用过来做个if判断就好了),登录了正常存储并提交发布,没登陆的提示状态,增强用户体验;

②存储内容,还记得我们的全局变量comment吗,把comment、avatarUrl、nickName以及foodId对应我们先前定义的属性,使用云数据库的数据库操作语法进行添加(开放文档直接用);

③完善功能,就是提交后,input里面应该是空的了,这是个小细节。我的实现方法是,使用input标签的value属性,value就是输入的实际内容,即在用户输入时,value就在不断变化;在响应数据data中定义inval初值为空,并把inval对应到前端的value属性;那在提交事件的最后,我就可以通过再将data中的inval置为空值来实现清空输入框了。

④另一个小完善,如果用户没有输入或者一开始就输入空格怎么办,我们做个判断,拿我们的全局变量comment,如果comment是空值或者第一个字符是一个空格,我们就做出提示。(其他非法字符,看自己的需求实现)

所以代码如下

    //button标签的bindtap=“summit”
    summit: function (e) {
        if (this.data.login) { //判断登陆状态
            wx.showLoading({
                title: '上传中',
            })
            if (comment == "" || comment[0] == " ") { //非法输入判断
                wx.showToast({
                    title: '含不恰当空格',
                    icon: 'error'
                })
            } else {  //数据添加
                db.collection('comment').add({
                    data: {
                        avatarUrl: this.data.userInfo.avatarUrl,
                        nickName: this.data.userInfo.nickName,
                        foodId: foodId,
                        comment: comment
                    },
                    success: res => {
                        // console.log(res)
                        this.onShow() //数据刷新显示
                        this.setData({  //清空输入框
                            inval: "",
                        })
                        comment = ""
                        wx.showToast({
                            title: '提交成功',
                        })
                    },
                    fail: err => {
                        console.log(err);
                    }
                })
            }
        } else { //没有登录
            wx.showToast({
                title: '您还未登录',
                icon: 'none'
            })
        }
    },

4.评论的显示

那我们已经有了所有准备展示的信息了(所有店铺分别对应的评论以及对应发布者的信息)

①获取数据,我在生命周期onload方法中加载数据,具体流程也简单,使用云数据库的查询语法,条件就是foodId等于我们点进去的这个店铺的id(不知道怎么获取吗,其实前面就该提到这个了。。想想你应该怎么跳到对应点击的这个店铺的详情页嘞,不卖关子了,我的方法是在有所有店铺的页面,把点击到的店铺id传递给这个详情页面,用到的就是标签自定义data属性以及页面带参跳转,onload接收传递过来的参数,根据传过来的这个id来找到对应的店铺详情并展示,那这个id后面也就接着用来存储和这里的判断咯),获取到之后,给响应数据data中的commentList给它setData一下就好了;

②前端展示,wx:for就行了,遍历这个commentList来展示。

         //wxml
         <view wx:for="{{commentList}}" wx:key="_id">
            <view class="你自己定">
                <image src="{{item.avatarUrl}}" />
                <view class="你自己定">
                    <text>{{item.nickName}}</text>:
                    <view class="你自己定">
                        {{item.comment}}
                    </view>
                </view>
            </view>
        </view>
    //js js js
    onLoad(options) { //跳转过来带的参数
        let that = this
            //获取店铺详细信息
            db.collection("foodlist").where({ 
                _id: options.id
            }).get({ 
                success: res => {
                    that.setData({
                        foodDetail: res.data[0]
                    })
                },
            })
        // 获取评论
        db.collection('comment').where({
                foodId: foodId
        }).get().then(res => {
                that.setData({
                    commentList: res.data.reverse()
                })
            })
        })
    },

但是还没结束,要记住小程序查询数据库默认只查20条记录噢!

这意味着什么呢,意味着我们要做分页啦~

5.功能完善,实现分页

那么提到数据库的分页,我们就要立刻想到 limit() 以及 skip() 了。

首先说一下,如上所述我的评论信息是没有存储发布时间这一项的,所以我的分页会很另类;如果你有存储时间,那简单了,你可以使用asc或desc配合查询语句来实现评论的后发先展示,然后分页就配合 limit() 和 skip() 做查询再进行数据拼接就好了,百度一找一大堆噢,你可以跳过这个第5点了噢~~

5.1评论的正常显示顺序(后发的在前面)

云数据库中,每条记录存下来成一个集合,每次添加记录都会添加在集合的最后,所以我的理解是最后一条记录就是最新的评论,所以怎么办嘞,我选择反转查询数据库查询下来的数组,这样也算是实现了最新评论的效果吧。

数组反转:

let newArr = arr.reverse()

这就带来了问题,集合中超过20条记录,那我就要从后往前拿,再做反转才能实现最新评论了。那就开始吧,配合上我们的 limit() 以及 skip() ,我要每次拿20条,我的首次加载的limit就给20咯;skip怎么给呢,按照上面说法,我要拿的就是倒数20条记录了,非常简单,我们用记录总数减去20不就行啦,获取记录总数,数据库查询语句的count拿就行了,拿到count,那么currentSkip就等于count - 20咯,最后把这些嵌到前边写的onload中的数据查询就好啦(记得反转噢)。

    onLoad(options) {
        let that = this

        ······

        // 获取评论
        db.collection('axx_comment').where({
            foodId: foodId
        }).count().then(res => {
            let count = res.total //总数拿到了
            let currentSkip = count - 20 //当前skip
            //开始拿数据
            db.collection('comment').limit(20).skip(currentSkip).where({
                foodId: foodId
            }).get().then(res => {  
                that.setData({
                    //记得反转
                    commentList: res.data.reverse()
                })
            })
        })
    },

5.2分页(加载更多)

做分页,变化的重点就是 skip() 的参数了。因为我的上述做法,这一步又多了许多要考虑的问题,那就是之后的skip参数我肯定不是加20了,而是减20,那就要考虑不够20减的情况了,这又带出另一个问题,skip不够20减,我们肯定就让它为0开始咯,那我的limit再拿20条的话,就会拿到重复数据了。

当然首次加载数据的情况,即onload中,我们不需要考虑limit的问题,记录多于20条和少于20条都没有影响;只要加一个currentSkip的判断就好了。

    onLoad(options) {
        let that = this

        ······

        // 获取评论
        db.collection('axx_comment').where({
            foodId: foodId
        }).count().then(res => {
            let count = res.total //总数拿到了
            let currentSkip //当前skip
            //做判断
            if (count - 20 < 0) {
                currentSkip = 0
            } else {
                currentSkip = count - 20
            }
            //开始拿数据
            db.collection('comment').limit(20).skip(currentSkip).where({
                foodId: foodId
            }).get().then(res => {  
                that.setData({
                    //记得反转
                    commentList: res.data.reverse()
                })
            })
        })
    },

开始分页 加载更多

首先我们将刚刚提到的count变量和currentSkip变量,都做变量提升,我把它们设置为全局变量;另外,我们还要设置一个全局变量showLength(已显示的评论数,主要用来判断到底够不够20减),方便做分页。

var currentSkip //从哪开始
var count //记录总数
var showLength //已显示评论数

定义一个加载更多的方法,我是 moreComment() ,然后要触底加载还是点击事件加载随便你。这一步我们就需要考虑上面提出的问题了。

首先showLength的初值在首次onload加载的回调中进行赋值就好了,就是 showLength = res.data.length,然后在每次加载更多中都进行更新,就是自身再加 res.data.length;

在 moreComment() 我们首先就可以使用 count - showLength 来判断还有没有数据可以加载,并给出反馈。有数据的情况,这里又分两种情况,①剩余数据小于20条的情况,那么我们的skip参数就是0,limit参数就是 count - showLength 了;②剩余数据大于20条的情况,简单了,skip参数就是 currentSkip - 20 ,limit参数就还是20了。

最后数据拼接,要注意的就是新数据反转后再拼接,showLength更新。

    onLoad(options) {
        let that = this

        ······

        // 获取评论
        db.collection('axx_comment').where({
            foodId: foodId
        }).count().then(res => {
            count = res.total //总数(变量已提升,下同)
            //开始位置
            if (count - 20 < 0) {
                currentSkip = 0
            } else {
                currentSkip = count - 20
            }
            //开始拿数据
            db.collection('comment').limit(20).skip(currentSkip).where({
                foodId: foodId
            }).get().then(res => {  
                that.setData({
                    //记得反转
                    commentList: res.data.reverse()
                })
                //已显示评论数
                showLength = res.data.length 
            })
        })
    },

    //加载更多
    moreComment() {
        let that = this
        wx.showLoading({
            title: '加载更多',
        })
        //没有数据了
        if (count - showLength == 0) {
            wx.showToast({
                title: '没有更多了',
                icon: 'none'
            })
        } 
        else {
            let skip //开始位置
            let max  //加载条数
            //少于20条
            if (count - showLength < 20) {
                max = count - showLength
                skip = 0
            } else { //多于20条
                max = 20
                skip = currentSkip - 20
            }
            db.collection('comment').limit(max).skip(skip).where({
                foodId: foodId
            }).get().then(res => {
                that.setData({
                    //新数据反转后与老数据拼接
                    commentList: that.data.commentList.concat(res.data.reverse())
                })
                //showLength更新
                showLength = showLength + res.data.length
                wx.showToast({
                    title: '加载成功',
                    icon: 'none'
                })
            })
        }
    },

最后,用你想要的方式来触发。

这里我自己碰到的问题是异步问题,当然不是上面的写法会出现的。

6.自己发的自己可以删除

这个就简单了,根据我们存云数据库的openid来设置谁可删除(当然是自己),点击删除,就从数据库中删除这条记录(如何获取这条记录?参考上面获取foodId的方法,获取这条评论的id),最后做一个数据刷新。这块内容网上一找也是一大堆噢~

三、总结

用了奇奇怪怪的方法;

碰到异步执行引发的相关问题(以后再说);

新评论发布时,做数据刷新显示,记得count、currentSkip、showLength也要刷新。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值