渲染评论
当我们打开文章详细页时,能够看到一条条的已有评论,这里我们先模仿博客园,采用评论楼的方式(如下)
后端数据
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> <span>{{ comment.create_time|date:'Y-m-d H:i' }}</span> <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> <span>'+ create_time +'</span> <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值来判断该评论是根评论还是子评论,再将评论的数据写入数据库
为了方便前端的实时显示,我们在这里取到了评论生成的时间和评论数传给前端