博客园-评论楼

 

渲染评论

当我们打开文章详细页时,能够看到一条条的已有评论,这里我们先模仿博客园,采用评论楼的方式(如下)

后端数据

def article_detail(request, username, article_id):
    article_obj = models.Article.objects.filter(pk=article_id).first()
    comment_list = models.Comment.objects.filter(article_id=article_id)
    return render(request, "blog/article_detail.html", {"username": username, "article_obj": article_obj, "comment_list": comment_list})

通过文章id取到该文章的所有评论

前端页面渲染

复制代码
<div class="comment_show">
        <p>评论楼:</p>
        <ul class="comment_list list-group">
            {% for comment in comment_list %}
                <li class="comment_item list-group-item">
                    <div class="row">
                        <div class="col-md-offset-1">
                            <a>#{{ forloop.counter }}楼</a>&nbsp;&nbsp;
                            <span>{{ comment.create_time|date:'Y-m-d H:i' }}</span>&nbsp;&nbsp;
                            <span>{{ comment.user.username }}</span>
                            <div class="pull-right"><a class="reply-btn" comment_id="{{ comment.pk }}"
                                                       comment_user="{{ comment.user.username }}">回复</a></div>
                        </div>
                    </div>
                    {% if comment.parent_comment_id %}

                    <div class="row">
                        <div class="col-md-offset-1 parent_comment_info well">
                            <a>@{{ comment.parent_comment.user.username }}</a>
                            <span>{{ comment.parent_comment.content }}</span>
                        </div>

                    </div>
                    {% endif %}
                    <div class="row">
                        <div class="col-md-offset-1">
                            <p>
                                {{ comment.content }}
                            </p>
                        </div>

                    </div>
                </li>
            {% endfor %}

        </ul>
    </div>
复制代码

为了区别根评论和子评论,在前端页面中需要做判断

评论框

评论内容是显示在文章详细页内的,所以前端页面部分仍然写在文章详细页内

首先要有一个给用户输入评论的评论框

复制代码
<div class="comment clearfix">
        <p>
            昵称:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                      value="{{ request.user.nickname }}">
        </p>
        <label for="comment_area">评论内容</label>
        <p>
            <textarea name="" id="comment_area" cols="60" rows="10"></textarea>
        </p>
        <input type="button" value="提交" class="btn btn-default" id="comment_submit_btn">
    </div>
复制代码

这里的评论框我们使用textarea标签

提交评论事件

当用户在评论框输入内容后,点击提交按钮,我们使用ajax提交用户的评论内容

这里分为两种情况,用户提交的是根评论还是子评论

如果是子评论,我们应该通过点击每一条评论的回复来进行评论,这里我们需要给这个回复绑定一个点击事件

该点击事件要做到2个效果:

1.在评论框中聚焦

2.生成@用户名的内容

复制代码
// 绑定回复按钮事件
        var parent_comment_pk = "";
        $(".comment_item .reply-btn").click(function () {
            // 获取焦点
            $("#comment_area").focus();
            // 设置 @用户名
            var val = "@" + $(this).attr("comment_user") + "
";
            $("#comment_area").val(val);
            //获取回复评论的主键值parent_comment_pk
            parent_comment_pk = $(this).attr("comment_id")
        })
复制代码

这里的聚焦我们采用focus()功能,而@用户名内容我们采用拼接的方式生成,可以看到在前端页面上我们为了方便取到被评论的用户以及父评论id,我们给回复的标签设置两条自定义属性

comment_id="{{ comment.pk }}"   comment_user="{{ comment.user.username }}"

提交按钮事件

复制代码
// 提交评论事件
        $("#comment_submit_btn").click(function () {
            // parent_comment_pk区分根评论和子评论
            if (parent_comment_pk) {
                // 子评论
                var content = $("#comment_area").val();
                var index = content.indexOf("
");
                content = content.slice(index + 1)
            } else {
                // 根评论
                var content = $("#comment_area").val();
            }

            // 清空输入框的内容
            $("#comment_area").val("");

            $.ajax({
                url: "/blog/comment/",
                type: "post",
                data: {
                    "content": content,
                    "article_id": "{{ article_obj.pk }}",
                    "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
                    "pid": parent_comment_pk
                },
                success: function (data) {
                    var data = JSON.parse(data);
                    var count = data.split(",")[0];
                    var create_time = data.split(",")[1];
                    var s = '<li class="comment_item list-group-item"><div class="row"><div class="col-md-offset-1"> <a>#'+ count +'楼</a>&nbsp;&nbsp; <span>'+ create_time +'</span>&nbsp;&nbsp; <span>'+ '{{ request.user.username }}' + '</span> </div> </div> <div class="row"><div class="col-md-offset-1"><p>'+ content +'</p> </div> </div> </li>';
                    $(".comment_list").append(s)
                }
            })
        });
复制代码

通过上面的事件,我们可以看到我们通过声明了一个parent_comment_pk的变量,如果点击了回复按钮就给他附上父评论的id值,没有点击他则为空

在点击提交按钮时,通过他的值来判断该评论是根评论还是子评论

当点击完后,我们还要在页面不刷新时就看到自己的评论,这里通过ajax的回调函数实现

后端处理

复制代码
def comment(request):
    content = request.POST.get("content")
    article_id = request.POST.get("article_id")
    user_id = request.user.nid
    pid = request.POST.get("pid")
    with transaction.atomic():
        if pid:  # 子评论
            comment = models.Comment.objects.create(content=content, article_id=article_id, user_id=user_id,
                                                    parent_comment_id=pid)
        else:  # 根评论
            comment = models.Comment.objects.create(content=content, article_id=article_id, user_id=user_id)
        models.Article.objects.filter(pk=article_id).update(comment_count=F("comment_count") + 1)
        count = models.Comment.objects.filter(article_id=article_id).count()
        create_time = str(comment.create_time)[:16]
        response = str(count) + "," + create_time
    return HttpResponse(json.dumps(response))
复制代码

通过前端传来的pid值来判断该评论是根评论还是子评论,再将评论的数据写入数据库

为了方便前端的实时显示,我们在这里取到了评论生成的时间和评论数传给前端

原文地址:https://www.cnblogs.com/QQ279366/p/8484274.html