Skip to content

点赞功能

需求分析

  • 后端提供点赞和取消点赞功能
  • 当用户点击未点赞按钮,执行点赞逻辑,向后端发起点赞请求,取消点赞则反之
  • 在文章显示完成之后,底部评论会根据当前登录用户显示是否点赞图标

点赞逻辑实现

前端逻辑实现

给点赞的 a 标签添加自定义属性,以记录当前点赞的文章id和评论id,供点赞/取消点赞请求使用

html
<a href="javascript:;" class="comment_up" style="float: right">赞</a>

实现点赞逻辑

JavaScript
// 实现点赞逻辑
$('.comment_list').on('click', '.comment_up', function () {
    let action = 'add';

    let that = this

    if ($(this).hasClass('has_comment_up')) {
        // 如果当前该评论已经是点赞状态,再次点击会进行到此代码块内,代表要取消点赞
        action = 'remove';
    }

    const comment_id = $(this).parents('.comment_info').attr('data-cid');
    const params = {
        'comment_id': comment_id,
        'action': action,
        'article_id': article_id,
    };

    $.ajax({
        url: '/api/v1/comment_like',
        type: 'post',
        contentType: 'application/json',
        data: JSON.stringify(params),
        success: function (resp) {
            console.log(resp)
            if (resp.code === 0) {
                $(that).toggleClass('has_comment_up')
            } else {
                layer.msg(resp.message);
            }
        }
    });
});

后端代码实现

application/apis/index.py 中添加点赞/取消点赞视图函数

python
@index_api.post("/comment_like")
@jwt_required()
def comment_like_view():
    # 获取参数
    article_id = request.json.get("article_id")
    comment_id = request.json.get("comment_id")
    action = request.json.get("action")

    # 查询评论数据
    try:
        comment: CommentORM = CommentORM.query.get(comment_id)
    except Exception as e:
        current_app.logger.error(e)
        return {'code': -1, 'success': False, 'message': '点赞的评论不存在'}

    if not comment:
        return {'code': -1, 'success': False, 'message': '点赞的评论不存在'}

    if action == 'add':
        #  如果点在已经存在,则会出问题
        comment_like = CommentLikeORM()
        comment_like.user_id = current_user.id
        comment_like.comment_id = comment_id
        comment_like.save()
        comment.like_count += 1
        comment.save()
    else:
        comment_like = CommentLikeORM.query.filter_by(comment_id=comment_id, user_id=current_user.id).first()
        comment_like.delete()
        comment.like_count -= 1
        comment.save()
    return {"code": 0, "msg": "操作成功"}

点赞计数功能

实现评论如果有点赞,就显示点赞的条数,并使用自定义属性记录当前条数

后端-返回数据

返回评论是否是被当前用户点赞

python
@index_api.get("/article/<int:article_id>/comment")
@jwt_required()
def comment_view(article_id):
    q = db.select(CommentORM)
    q = q.where(CommentORM.article_id == article_id)
    q = q.where(CommentORM.parent_id == None)
    q = q.order_by(CommentORM.create_at.desc())
    ret: [CommentORM] = db.session.execute(q).scalars()

    user_like_comment = current_user.comment_like_list.all()  
    user_like_comment_id = [c.comment_id for c in user_like_comment]  
    ret_list = []  
    for comment in ret:
        comment: CommentORM
        d = comment.as_json()
        d['nickname'] = comment.user.nickname
        d['avatar_url'] = comment.user.avatar_url
        d['user_like'] = comment.id in user_like_comment_id  
        if comment.child:
            sub_ret_list = []
            for sub_comment in comment.child:
                sub_d = sub_comment.as_json()
                sub_d['nickname'] = sub_comment.user.nickname
                sub_d['avatar_url'] = sub_comment.user.avatar_url
                sub_d['user_like'] = sub_comment.id in user_like_comment_id  
                sub_ret_list.append(sub_d)
            d['child'] = sub_ret_list
        ret_list.append(d)

    return {"code": 0, "msg": "获取评论成功", "data": ret_list}

前端-渲染点赞数据

然后前端渲染评论点赞数量

javascript
function render_sub_comment(child) {
  let sub_comment_html = "";
  child.forEach((article) => {
    sub_comment_html += `<div class="sub-comment">
            <div class="sub-username">${article.nickname}</div>
            <div class="comment_text">
                ${article.content}
            </div>
            <div class="comment_info" data-cid="${article.id}">
                <div class="comment_time">${dayjs(article.create_at).format(
                  "YYYY-MM-DD HH:mm:ss",
                )}</div>
                 <a href="javascript:;" class="comment_up ${
                   article.user_like ? "has_comment_up" : ""
                 }" style="float: right">${
                   article.like_count || "赞"
                 }</a>
                <a href="javascript:;" class="comment_reply">回复</a>
            </div>
        </div>
`;
  });
  return sub_comment_html;
}

// 加载文章的评论 登录之后才能查看评论
if (isLogin()) {
  $.ajax({
    url: `/api/v1/article/${article_id}/comment`,
    type: "get",
    success: function (res) {
      res.data.forEach((article) => {
        let article_html = `
                <div class="comment">
                    <div class="person_pic">
                        <img src="${
                          article.avatar_url || "/static/images/worm.jpg"
                        }" alt="用户图标">
                    </div>
                    <div class="comment-content">
                        <div class="username">${article.nickname}</div>
                        <div class="comment_text">
                            ${article.content}
                        </div>
                        <div class="comment_info" data-cid="${article.id}"> 
                            <div class="comment_time">${dayjs(
                              article.create_at,
                            ).format("YYYY-MM-DD HH:mm:ss")}</div>
                            <a href="javascript:;" class="comment_up ${
                              article.user_like ? "has_comment_up" : ""
                            }" style="float: right">${
                              article.like_count || "赞"
                            }</a>
                            <a href="javascript:;" class="comment_reply">回复</a>
                        </div>
                    `;

        if (article.child !== undefined) {
          article_html += render_sub_comment(article.child);
        }

        article_html += `
                         </div>
                        </div>
                    `;
        $(".comment_list").append(article_html);
      });
    },
  });
}

前端-动态调整点赞数

javascript
// 实现点赞逻辑
$(".comment_list").on("click", ".comment_up", function () {
  let action = "add";

  let that = this;

  if ($(this).hasClass("has_comment_up")) {
    // 如果当前该评论已经是点赞状态,再次点击会进行到此代码块内,代表要取消点赞
    action = "remove";
  }

  const comment_id = $(this).parent(".comment_info").attr("data-cid");
  const params = {
    comment_id: comment_id,
    action: action,
    article_id: article_id,
  };

  $.ajax({
    url: "/api/v1/comment_like",
    type: "post",
    contentType: "application/json",
    data: JSON.stringify(params),
    success: function (resp) {
      console.log(resp);
      if (resp.code === 0) {
        if ($(that).hasClass("has_comment_up")) {

          let count = parseInt($(that).text()); 
          if (count == 1) {

            $(that).text("赞"); 
          } else {

            $(that).text(parseInt($(that).text()) - 1); 
          } 
        } else {

          if ($(that).text() == "赞") {

            $(that).text("1"); 
          } else {

            $(that).text(parseInt($(that).text()) + 1); 
          } 
        } 
        $(that).toggleClass("has_comment_up");
      } else {
        layer.msg(resp.message);
      }
    },
  });
});