资讯专栏INFORMATION COLUMN

Django搭建个人博客:锚点定位

xi4oh4o / 2911人阅读

摘要:在父页面中文章详情模板添加需要执行锚点拼接的函数新增函数,处理二级回复去除尾部符号刷新并定位到锚点函数中运用了的三元运算符,翻译成人话就是如果成立则返回,如果不成立就返回。

老读者注意:上一章消息通知有个bug,即发给管理员的notify必须移动到new_comment.save()的后面,否则会导致action_object存储为NULL,并且导致本章的html拼接锚点失效。

原文已更正,为博主的疏忽表示歉意。

上一章已经实现了消息通知功能,可以很人性化的把用户引导到被他人回复的页面中去。

但是仔细想想,似乎还有不方便的地方:如果页面中评论较多,想找到感兴趣的那一条评论还是要费点功夫的。所以这个消息通知,最好是能够不仅前往正确的页面,还要前往正确的位置(需求是无穷无尽的..)。

为了实现这个功能,本章就要介绍一个非常古老的功能:锚点定位。以及如何在Django中实现它。

锚点是什么

我们在写html文件的容器时,经常会用到id属性:

apple

这个id属性不仅可以作为Javascript或者css代码查询某个容器的标记,还可以作为锚点,定位页面应该前往的位置。输入下面的地址:

http://www.myblog.com/home#fruit

浏览器就会打开home页面,并且视窗前往id="fruit"的容器。

明白了锚点是什么,下面就通过三种不同的实现方法,看看锚点在Django博客项目中是如何应用的。

三种实现 html拼接

锚点首先要实现的功能,就是当管理员点击消息通知时,浏览器视窗前往此通知的评论位置

因此首先修改文章详情页面,给渲染评论的div容器添加id属性:

templates/article/detail.html

...

{% recursetree comments %}
{% with comment=node %}


...
{{ children }}
{% endif %}
{% endwith %} {% endrecursetree %} ...

我们还是用comment.id来给每条评论赋予唯一的id值。注意id属性保持唯一性。前面在二级回复的Modal中用了comment_{{ comment.id }},这里千万不要重复了。

然后修改通知列表模板,添加锚点:

templates/notice/list.html

...
{% for notice in notices %}
  • ... ...
  • {% endfor %} ...

    注意这里url中拼接了两种玩意儿:

    跟在?后面的是查询参数,用于给视图传递参数,是之前写的旧代码

    跟在#后面的是锚点,也就是本章正在学的东东

    ?#一个重要的差别,就是?不能够传递到下个页面的url中去,而#可以。

    测试一下,用普通用户账号发几条一级评论,登录管理员账号并点击消息通知:

    浏览器视窗没有在页面顶部,而是直接前往到该条评论处。

    通过html拼接是实现锚点最简单直接的方法。

    视图拼接

    html拼接虽好,但它不是万能的。如果要前往一个当前页面还没有创建的容器,该怎么办?

    举个栗子。按照目前我们的博客设计,当用户发表评论时,页面会刷新、视窗将停留在文章详情的顶部。但实际上这时候视窗应该停留在新发表的评论处才比较合理,因为用户可能想检查一下自己发表的评论是否正确。而在原页面时由于新评论都还没发表,所以comment.id是不存在的,没办法用html拼接锚点。读者好好思考一下是不是这样。

    这种情况下就需要在视图中拼接锚点了。修改文章评论视图,将锚点拼接到redirect函数中:

    comment/views.py
    
    ...
    # 文章评论视图
    def post_comment(request, article_id, parent_comment_id=None):
        ...
        # 已有代码
        if request.method == "POST":
            ...
            if comment_form.is_valid():
                ...
                if parent_comment_id:
                    ...
                new_comment.save()
                if not request.user.is_superuser:
                    notify.send(...)
    
                # 新增代码,添加锚点
                redirect_url = article.get_absolute_url() + "#comment_elem_" + str(new_comment.id)
                # 修改redirect参数
                return redirect(redirect_url)
    get_absolute_url()是之前章节写的方法,用于查询某篇文章的地址。

    说白了就是把拼接的位置从模板挪到了视图中,因为新评论必须在视图中保存之后才会被分配一个id值。

    流动的数据

    最后我们来看稍微复杂点的情况。

    当用户发表一级评论时,我们在视图中拼接锚点解决了刷新当前页面并定位的问题。但是二级评论是通过iframe + ajax实现的,这又该怎么办?

    理一理思路。

    首先,新评论的id值是在视图中创建的,但是由于视图是从iframe中请求的,在视图中没办法刷新iframe的父页面。所以我们唯一能做的就是把数据传递出去,到前端去处理。

    修改文章评论视图:

    comment/views.py
    
    # 引入JsonResponse
    from django.http import JsonResponse
    
    ...
    # 文章评论视图
    def post_comment(request, article_id, parent_comment_id=None):
        article = get_object_or_404(ArticlePost, id=article_id)
    
        # 已有代码
        if request.method == "POST":
            ...
            if comment_form.is_valid():
                ...
                if parent_comment_id:
                    ...
    
                    # 修改此处代码
                    # return HttpResponse("200 OK")
                    return JsonResponse({"code": "200 OK", "new_comment_id": new_comment.id})
    
                ...

    新引入的JsonResponse返回的是json格式的数据,由它将新评论的id传递出去。

    json是web开发中很常用的轻量级数据格式,非常像python的字典,读者请自行了解。

    特别提醒json格式必须用双引号。

    现在数据在iframe中了。但是我们需要刷新的是iframe的父页面啊,所以还要继续把数据往父页面“扔"

    修改二级评论的模板:

    templates/comment/reply.html
    
    ...
    

    由于现在ajax获取的是json数据,因此用e.code获取视图返回的状态。

    旧代码用parent.location.reload()刷新了父页面。同样的,用parent.abc()可以调用父页面的abc()函数。这样就把数据传递到父页面里去了。

    这下就好说了。在父页面中(文章详情模板)添加需要执行锚点拼接的函数:

    templates/article/detail.html
    
    ...
    
    {% block script %}
    ...
    
    {% endblock script %}

    函数中运用了JavaScript三元运算符a ? b : c,翻译成人话就是:如果a成立则返回b,如果a不成立就返回c。作用是去掉url尾部的/,否则锚点不会生效。你可能会问,三元运算符多麻烦,为什么不直接把url末尾一个字符剔除掉呢?答案是这样写代码更加健壮。万一哪天Django解析的url尾部没有斜杠了呢。

    window.location.replace()作用是重定向页面,在这里面终于可以愉快的拼接锚点了。

    一切都OK啦。测试发表二级评论,运气好的同学应该可以顺利将视窗定位到刚评论的位置了。

    感受到数据的流动没有?

    总结

    本章学习了锚点的html拼接、视图拼接、ajax+iframe综合运用,理解后就能应付绝大部分的状况了。

    锚点虽然古老,但并不陈旧。

    合理的运用锚点,可以让你的博客相当的人性化,这也是好网站的一个标志。


    有疑问请在杜赛的个人网站留言,我会尽快回复。

    或Email私信我:dusaiphoto@foxmail.com

    项目完整代码:Django_blog_tutorial

    文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

    转载请注明本文地址:https://www.ucloud.cn/yun/43948.html

    相关文章

    • Django搭建个人博客:渲染Markdown文章目录

      摘要:博文也是同样的,好的目录对博主和读者都很有帮助。文中的目录之前我们已经为博文支持了语法,现在继续增强其功能。修改文章详情视图文章详情目录扩展仅仅是将将扩展添加了进去。通过将目录传递给模板。 对会读书的人来说,读一本书要做的第一件事,就是仔细阅读这本书的目录。阅读目录可以对整体内容有所了解,并清楚地知道感兴趣的部分在哪里,提高阅读质量。 博文也是同样的,好的目录对博主和读者都很有帮助。更...

      Bamboy 评论0 收藏0
    • Django搭建个人博客:创建并配置APP功能模块

      摘要:创建在中的一个代表一个功能模块。就是项目的基石,因此开发博客的第一步就是创建新的,用来实现跟文章相关的功能模块。注意之后,的必须配置,否则会报错。总结本章创建了博客文章功能的,学习了注册并配置。 创建APP 在Django中的一个app代表一个功能模块。开发者可以将不同功能的模块放在不同的app中, 方便代码的复用。app就是项目的基石,因此开发博客的第一步就是创建新的app,用来实现...

      沈俭 评论0 收藏0
    • Django搭建个人博客:改写View视图

      摘要:改写视图函数上一章我们感受了视图的工作流程。循坏表示依次取出中的元素,命名为,并分别执行接下来操作。即为语言,中间包裹了一个段落的文字。有疑问请在杜赛的个人网站留言,我会尽快回复。 改写视图函数 上一章我们感受了视图的工作流程。 为了让视图真正发挥作用,改写article/views.py中的article_list视图函数: article/views.py from django...

      KaltZK 评论0 收藏0
    • Django搭建个人博客:编写文章详情页面

      摘要:有了文章列表页面后,当然还需要详情页面,方便用户对某一篇感兴趣的文章深入阅读。编写视图函数打开,增加文章详情页面的视图函数文章详情取出相应的文章需要传递给模板的对象载入模板,并返回对象函数中多了这个参数。 有了文章列表页面后,当然还需要详情页面,方便用户对某一篇感兴趣的文章深入阅读。 编写视图函数 打开article/views.py,增加文章详情页面的视图函数article_deta...

      dabai 评论0 收藏0
    • Django搭建个人博客:用django-notifications实现消息通知

      摘要:接下来你就可以在项目的任何地方发送通知了像这样其中的参数释义发送通知的对象接收通知的对象动词短语链接到动作的对象可选执行通知的对象可选有点绕,举个栗子杜赛在搭建个人博客中对你发表了评论。有疑问请在杜赛的个人网站留言,我会尽快回复。 凭借你勤奋的写作,拜读你文章的用户越来越多,他们的评论也分散在众多的文章之中。作为博主,读者的留言肯定是要都看的;而读者给你留言,自然也希望得到回复。 怎么...

      Zoom 评论0 收藏0

    发表评论

    0条评论

    xi4oh4o

    |高级讲师

    TA的文章

    阅读更多
    最新活动
    阅读需要支付1元查看
    <