让评论页默认显示两条两条数据,其余数据通过点击加载更多来实现ajax的加载,同时提交评论后显示的是提交评论之前加载出来的评论。
大致思路:
定义一个用于记录加载评论的值offset(即偏移量),这个值在所有需要加载评论的地方都需要使用。
设置方法:无论是在ajax请求还是评论之后,都需要将记录偏移量的值同步到cookie中,这样每次请求评论的时候都可以通过调用这个值来确定要加载出来的值。
1、进入详情页时访问的视图函数如下:
在进入详情页的时候获取cookie中的offset的值就可以确定要加载多少条数据,故而在评论之后直接重定向到详情页即可
def detail(request, article_id):
article = Article.objects.get(id=article_id)
comment_form = CommentForm()
# 从cookie中获取要访问到第几个数据,这样在刷新此页面的时候就可以确定要加载多少数据了
offset = int(request.COOKIES.get('offset'))
comments = article.comment_set.all()[0:offset]
return render(request, 'article_page.html', locals())
2、前台ajax请求的相应代码
<script>
String.prototype.format= function() {
if(arguments.length === 0) return this;
var param = arguments[0], str= this;
if(typeof(param) === 'object') {
for(var key in param)
str = str.replace(new RegExp("\\{" + key + "\\}", "g"), param[key]);
return str;
} else {
for(var i = 0; i < arguments.length; i++)
str = str.replace(new RegExp("\\{" + i + "\\}", "g"), arguments[i]);
return str;
}
};
{# 以上代码是通过自定义来实现python中的.format()函数的功能,因为前段语言中没有内置的类似于.format()的函数 #}
{# offset:是需要传给后台的参数用于获取评论的参数。评论偏移量,表示次请求应该从索引为2的位置开始获取,默认索引为0、1的评论已经展示过了。 #}
offset = parseInt('{{ offset }}');
$('#more').click(function () {
{# offset += 2;修改偏移量,用于确定后续的加载 #}
offset += 2;
$('input[name="offset"]').val(offset);
$.ajax({
url: '{% url "more" %}',
data: {
'offset': offset,
'article_id': {{ article.id }}
},
success: function (data, status) {
{# data,这个参数,是后台返回的数据,此时后台需要返回JSON字符串。前端解析JSON字符串,并将相应的结果展示在页面中。 #}
console.log(data, status);
var comments = data['comments'];
for (var i=0; i<comments.length; i++){
{# 利用i为索引,从comments数组中获取对应的评论内容。 #}
var comment = comments[i];
{# 利用js向页面中插入两条评论 #}
result = '<div class="row"><article class="col-xs-12"><p class="pull-right"><span class="label label-primary">{date}</span> <span class="label label-default">{user}</span></p><a class="pull-right" href="/poll/{article_id}/?comment_id={comment_id}"><span class="glyphicon glyphicon-thumbs-up"></span>{poll_num} 点赞</a><p>{content}</p></article></div><hr>'.format(comment);
{# before():指定就是在当前DOM元素的前面追加DOM元素。 #}
$('#more').before(result);
}
}
});
{# return false;阻止a标签默认的GET请求事件。 #}
return false;
})
</script>
3、对应上述前段代码的后台程序代码
def more(request):
# 获取前端传过来的评论偏移量
offset = int(request.GET.get('offset'))
# 根据这个偏移量查询出来两条评论,需要先获取当前这个文章的所有评论
article = Article.objects.get(id=request.GET.get('article_id'))
comments = article.comment_set.all()[offset-2: offset]
# 将所有评论转化成JSON字符串,返回给前端{'comments': [{}, {}, {}]}
comments_dict = {}
comments_list = []
for comment in comments:
dic = {}
dic['content'] = comment.content
artilce_date = str(comment.date.year) + '年' + str(comment.date.month) + '月' + str(comment.date.day) + '日' + ' ' + str(comment.date.hour) + ':' + str(comment.date.minute)
dic['date'] = artilce_date
dic['poll_num'] = comment.poll_num
dic['user'] = comment.user.uname
dic['article_id'] = comment.article.id
dic['comment_id'] = comment.id
comments_list.append(dic)
comments_dict['comments'] = comments_list
# 将offset的值更新如cookie中
response = JsonResponse(comments_dict)
response.set_cookie('offset', offset)
return response
4、以上代码看似已经完成了功能要求,但是有一个致命的问题:当切换其他新闻进行浏览的时候,从cookie中获取offset的值的时候,不是从默认的2开始的,而是之前已经更新的cookie中的offset的值。
要解决这个问题也很简单:只需要在每次回到首时将cookie中的offset的值更新为默认的2就行了如下代码:
def index(request):
login_form = LoginFrom()
articles = Article.objects.all()
# 将要返回的渲染页面先复制给response
response = render(request, 'index.html', locals())
# 然后通过response操作cookie,将offset的默认值值写入cookie,这样就可以解决不同新闻之间的offset值的串联的问题了
response.set_cookie('offset', 2)
return response