锚点定位
上一章已经实现了消息通知功能 ,可以很人性化的把用户引导到被他人回复的页面中去。
但是仔细想想,似乎还有不方便的地方:如果页面中评论较多,想找到感兴趣的那一条评论还是要费点功夫的。所以这个消息通知,最好是能够不仅前往正确的页面,还要前往正确的位置(需求是无穷无尽的..)。
为了实现这个功能,本章就要介绍一个非常古老的功能: 锚点定位 。以及如何在Django中实现它。
锚点是什么
我们在写html文件的容器时,经常会用到id属性:
这个id属性不仅可以作为Javascript或者css代码查询某个容器的标记,还可以作为锚点,定位页面应该前往的位置。输入下面的地址:
浏览器就会打开home页面,并且视窗前往id="fruit"的容器。
明白了锚点是什么,下面就通过三种不同的实现方法 ,看看锚点在Django博客项目中是如何应用的。
三种实现
html拼接
锚点首先要实现的功能,就是当管理员点击消息通知时,浏览器视窗前往此通知的评论位置。
因此首先修改文章详情页面,给渲染评论的div容器添加id属性:
我们还是用comment.id来给每条评论赋予唯一的id值。注意id属性保持唯一性 。前面在二级回复的Modal中用了comment_{{ comment.id }} ,这里千万不要重复了。
然后修改通知列表模板,添加锚点:
注意这里url中拼接了两种玩意儿:
跟在
?后面的是查询参数,用于给视图传递参数,是之前写的旧代码跟在
#后面的是锚点,也就是本章正在学的东东
?和#一个重要的差别,就是?不能够传递到下个页面的url中去,而#可以。
测试一下,用普通用户账号发几条一级评论,登录管理员账号并点击消息通知:

浏览器视窗没有在页面顶部,而是直接前往到该条评论处。
通过html拼接是实现锚点最简单直接的方法。
视图拼接
html拼接虽好,但它不是万能的。如果要前往一个当前页面还没有创建的容器 ,该怎么办?
举个栗子。按照目前我们的博客设计,当用户发表评论时,页面会刷新、视窗将停留在文章详情的顶部。但实际上这时候视窗应该停留在新发表的评论处才比较合理,因为用户可能想检查一下自己发表的评论是否正确。而在原页面时由于新评论都还没发表,所以comment.id是不存在的,没办法用html拼接锚点。读者好好思考一下是不是这样。
这种情况下就需要在视图中拼接锚点了。修改文章评论视图,将锚点拼接到redirect函数中:
get_absolute_url()是之前章节写的方法,用于查询某篇文章的地址。
说白了就是把拼接的位置从模板挪到了视图中,因为新评论必须在视图中保存之后才会被分配一个id值。
流动的数据
最后我们来看稍微复杂点的情况。
当用户发表一级评论时,我们在视图中拼接锚点解决了刷新当前页面并定位的问题。但是二级评论是通过iframe + ajax实现的,这又该怎么办?
理一理思路。
首先,新评论的id值是在视图中创建的,但是由于视图是从iframe中请求的,在视图中没办法刷新iframe的父页面。所以我们唯一能做的就是把数据传递出去 ,到前端去处理。
修改文章评论视图:
新引入的JsonResponse返回的是json格式的数据,由它将新评论的id传递出去。
json是web开发中很常用的轻量级数据格式,非常像python的字典,读者请自行了解。
特别提醒json格式必须用双引号。
现在数据在iframe中了。但是我们需要刷新的是iframe的父页面啊,所以还要继续把数据往父页面“扔"。
修改二级评论的模板:
由于现在ajax获取的是json数据,因此用e.code获取视图返回的状态。
旧代码用parent.location.reload()刷新了父页面。同样的,用parent.abc()可以调用父页面的abc()函数。这样就把数据传递到父页面里去了。
这下就好说了。在父页面中(文章详情模板)添加需要执行锚点拼接的函数:
函数中运用了JavaScript的三元运算符a ? b : c ,翻译成人话就是:如果a成立则返回b ,如果a不成立就返回c 。作用是去掉url尾部的/ ,否则锚点不会生效。你可能会问,三元运算符多麻烦,为什么不直接把url末尾一个字符剔除掉呢?答案是这样写代码更加健壮。万一哪天Django解析的url尾部没有斜杠了呢。
window.location.replace()作用是重定向页面,在这里面终于可以愉快的拼接锚点了。
一切都OK啦。测试发表二级评论,运气好的同学应该可以顺利将视窗定位到刚评论的位置了。
感受到数据的流动没有?
总结
本章学习了锚点的html拼接、视图拼接、ajax+iframe综合运用,理解后就能应付绝大部分的状况了。
锚点虽然古老,但并不陈旧。
合理的运用锚点,可以让你的博客相当的人性化,这也是好网站的一个标志。
项目完整代码: Django_blog_tutorial