设计思路
先写根评论
先把整体的评论功能跑通
1.书写前端获取用户评论的标签 可能点赞点踩有浮动带来的影响
clearfix
2.点击评论按钮发送ajax请求
3.后端针对评论单独开设url处理
后端逻辑其实非常的简单非常的少
4.针对根评论涉及到前端的两种渲染方式
1.DOM操作临时渲染评论楼
需要用到模版字符串
// 临时渲染评论楼
let userName = '{{ request.user.username }}';
let temp = `
<li class="list-group-item">
<span>${userName}</span>
<span><a href="#" class="pull-right">回复</a></span>
<div>
${conTent}
</div>
</li>
`
// 将生成好的标签添加到ul标签内
$('.list-group').append(temp);
2.页面刷新永久(render)渲染
后端直接获取当前文章对应的所有评论 传递给html页面即可
前端利用for循环参考博客园评论楼样式渲染评论
3.评论框里面的内容需要清空
再写子评论
从回复按钮入手
点击回复按钮发生了几件事
1.评论框自动聚焦 .focus()
2.将回复按钮所在的那一行评论人的姓名@出来并且换行
@username\n
思考:
1.根评论和子评论点的是同一个按钮
2.根评论和子评论的区别
其实之前的ajax代码只需要添加一个父评论id即可
点击回复按钮之后 我们应该获取到根评论对应的用户名和主键值
针对主键值 多个函数都需要用 所以用全局变量的形式存储
针对子评论内容 需要切割出不是用户写的 @username\n
后端parent字段本来就可以为空,所以传不传值都可以直接存储数据
前端针对子评论再渲染评论楼的时候需要额外的判断
{% if comment.parent_id %}
<p>@{{ comment.parent.user.username }}</p>
{% endif %}
{{ comment.content }}
前端parentId字段每次提交之后需要手动清空
后端代码
from django.db import transaction
def comment(request):
# 自己也可以给自己的文章评论内容
if request.is_ajax():
back_dic = {'code': 1000, 'msg': ''}
if request.method == 'POST':
if request.user.is_authenticated():
article_id = request.POST.get('article_id')
content = request.POST.get('content')
parent_id = request.POST.get('parent_id')
# 开启事务 直接操作评论表 存储数据 两张表
with transaction.atomic():
models.Article.objects.filter(pk=article_id).update(comment_num=F('comment_num')+1)
models.Comment.objects.create(user=request.user, article_id=article_id, content=content, parent_id=parent_id)
back_dic['msg'] = '评论成功!'
else:
back_dic['code'] = 1001
back_dic['msg'] = '用户未登录'
return JsonResponse(back_dic)
前端页面代码
<body>
{# 评论楼渲染开始#}
{# #1楼 2019-01-03 15:12 yuzhiboyou#}
<div>
<ul class="list-group">
{% for comment in comment_list %}
<li class="list-group-item">
<span>#{{ forloop.counter }}楼</span>
<span>{{ comment.comment_time|date:'Y-m-d h:i' }}</span>
<span>{{ comment.user.username }}</span>
<span><a class="pull-right reply" username="{{ comment.user.username }}" comment_id="{{ comment.pk }}">回复</a></span>
<div>
{#判断当前评论是否为子评论 如果是需要渲染对应的评论人姓名@xxx#}
{% if comment.parent_id %}
<p>@{{ comment.parent.user.username }}</p>
{% endif %}
{{ comment.content }}
</div>
</li>
{% endfor %}
</ul>
</div>
{# 评论楼渲染结束#}
{# 文章评论开始#}
{% if request.user.is_authenticated %}
<div>
<p><span class="glyphicon glyphicon-comment"></span>发表评论</p>
<div>
<textarea name="comment" id="id_comment" cols="60" rows="10"></textarea>
</div>
<button class="btn btn-primary" id="id_submit">提交评论</button>
<span style="color: red" id="errors"></span>
</div>
{% else %}
<li><a href="{% url 'login' %}">登录</a></li>
<li><a href="{% url 'reg' %}">注册</a></li>
{% endif %}
{# 文章评论结束#}
</body>
js部分 其中包括了回复功能
<script>
// 设置一个全局parentID字段
let parentId = null;
// 用户点击评论按钮朝后端发送ajax请求
$('#id_submit').off().click(function () {
// 获取用户评论内容
let conTent = $('#id_comment').val();
// 判断当前评论是否为子评论 如果是 需要将我们之前动手渲染的@username去除
if (parentId){
// 找到\n对应的索引值 然后利用切片 但是切片顾头不顾尾 所以索引+1
let indexNum = conTent.indexOf('\n') + 1;
conTent = conTent.slice(indexNum) // 将indexNum之前的所有内容切除 只保留后面的部分
}
$.ajax({
url:'/comment/',
type:'post',
data:{
'article_id': '{{ article_obj.pk }}',
'content': conTent,
// 如果parentID没有值 那么就是null 后端存储null没关系因为数据库中允许为null
'parent_id': parentId,
'csrfmiddlewaretoken': '{{ csrf_token }}'
},
success:function (args){
if(args.code == 1000){
$('#errors').text(args.msg)
// 将评论框里面的内容清空
$('#id_comment').val('')
// 临时渲染评论楼
let userName = '{{ request.user.username }}';
let temp = `
<li class="list-group-item">
<span>${userName}</span>
<span><a href="#" class="pull-right">回复</a></span>
<div>
${conTent}
</div>
</li>
`
// 将生成好的标签添加到ul标签内
$('.list-group').append(temp);
// 清空全局的parentId字段 要不然你不刷新页面继续评论的话一直是子评论
parentId = null;
}
}
})
})
// 给回复按钮绑定事件
$('.reply').click(function () {
// 需要评论对应的 评论人姓名 还需要评论的主键值
// 获取用户名
let commentUserName = $(this).attr('username');
// 获取主键值 直接修改全局的变量名
parentId = $(this).attr('comment_id');
// 将拼接信息塞给评论区
$('#id_comment').val('@' + commentUserName + '\n').focus()
})
</script>
标签:comment,username,功能,parent,request,评论,文章,id
From: https://www.cnblogs.com/piggthird/p/17790419.html