【问题标题】:How to put JavaScript at the bottom of Django pages when using templatetags?使用模板标签时如何将 JavaScript 放在 Django 页面的底部?
【发布时间】:2010-11-04 21:12:54
【问题描述】:

雅虎的Best Practices for Speeding Up Your Website 表示:

将脚本放在底部

我的 Django 应用程序中有两种类型的脚本:

  1. 包含在我的基本(例如继承)模板中的脚本;和
  2. 由模板标签实例化的模板内编写的脚本

支持 UI 控件的脚本必须是模板的一部分,因为它们支持模板标签来处理唯一 ID 等内容并将相关代码保持在一起。

问题是,如果我按照雅虎的建议将库(#1)放在页面底部,100% 包含的内联脚本(#2)将失败,因为库尚未加载和解析还没有。

我不能在我的基本模板中扩展 {% block %} 元素,因为我在模板标签的上下文中所做的任何事情都不会传播到它之外——按照设计,以避免变量名冲突(根据 Django 的文档)。

有谁知道如何将 JavaScript 从我的模板标签的模板中延迟到我的基本模板的底部呈现?

【问题讨论】:

    标签: javascript django templatetags


    【解决方案1】:

    我通常有这样的基本模板设置。

    <html>
    <head>
    
    {% block js-head %} Tags that need to go up top  {% endblock js-head %}
    
    </head>
    <body>
    {% block header %}  Header {% endblock header %}
    
    {% block body %} Body goes here {% endblock body %}
    
    {% block footer %}  Footer {% endblock footer %}
    
    {% block js-foot %}  All other javascript goes here {% endblock js-foot %}
    </body>
    </html>
    

    然后我可以扩展这个基本模板并且只覆盖我关心的块。我将所有不必放在 js-foot 标题中的 javascript 都放在了 js-foot 中,因为它位于模板的底部,所以它会最后加载。如果您必须移动 javascript 加载的位置,您只需在基本模板中移动 js-foot 块。

    没什么花哨的,但它确实有效。

    【讨论】:

    • 这也是我在最近的项目中开始采用的一种模式,Ken。感谢您的回答;我将其标记为已接受的答案,因为它简单且有效。不幸的是,它仍然没有解决在模板标签中嵌入脚本的问题,但似乎没有办法按照现在的方式来做到这一点。
    • 如果您在使用“包含”模板标签调用的任何模板部分中有 Javascript,则此方法将失败。这些包含文件无法将其 HTML 附加到主模板中的任何块中。
    【解决方案2】:

    将包含在内联的脚本包装在

    jQuery(function(){ ... });

    当 DOM 准备好并下载脚本时执行。

    另一种选择可能是创建某种自定义模板标签,例如:

    {% inlinescript %}
    // some javascript code.
    {% endinlinescript %}
    

    您可以在执行过程中使用它来聚合内联脚本。您需要在解析模板时聚合这些数据——这会变得很棘手,因为模板标签具有不同的上下文,而这是您希望将其存储在自定义变量中的全局上下文中,例如 inline_scripts

    我将看看 Django 在默认模板库中实现各种 with ... as .. 构造的方式,以了解如何将您自己的变量添加到上下文中。

    然后您可以在页面底部执行 {{ inline_scripts }}。

    最简单的解决方案是jQuery.ready(function(){}) / jQuery(function(){ })(这两种方法是同义词)。

    或者您可能想重新考虑雅虎的建议。内联 javascript 有一些积极的方面 - 它可以减少 FOUC / FOUBC(不行为内容的 Flash)。雅虎往往有点迂腐——(看看 YUI API ;)。如果您需要重写应用程序的某些部分以获得适度可察觉的性能改进,那可能不值得。


    进行脚本聚合(最初基于 django-sn-ps 上的捕获):

    @register.tag(name='aggregate')
    def do_aggregate(parser, token):
        try:
            tag_name, args = token.contents.split(None, 1)
        except ValueError:
            raise template.TemplateSyntaxError("'aggregate' node requires a variable name.")
        nodelist = parser.parse(('endaggregate',))
        parser.delete_first_token()
        return AggregateNode(nodelist, args)
    
    class AggregateNode(Node):
        def __init__(self, nodelist, varname):
            self.nodelist = nodelist
            self.varname = varname
    
        def render(self, context):
            output = self.nodelist.render(context)
            if context.has_key(self.varname):
                context[self.varname] += output
            else:
                context[self.varname] = output
            return ''
    

    用法:

    {% aggregate inline_scripts %}
    var foo = 'bar';
    {% endaggregate %}
    
    ... template code
    
    {% aggregate inline_scripts %}
    var baz = 'bar';
    {% endaggregate %}
    
    ... somewhere near the bottom of your page
    
    {{ inline_scripts }}
    

    【讨论】:

    • jQuery() 不起作用,因为尚未定义 jQuery。它会抛出一个错误。这就是问题的本质——在定义之前不能调用 jQuery,而首先定义它意味着忽略 Yahoo 的建议。另一种方法更接近我想要做的,但正如你所说,它很棘手——如何实际去做?
    • 呵呵,现在这个确实看起来很有趣。我稍后会试一试并报告。感谢您抽出宝贵时间整理这些资料;将投票赞成,因为它看起来应该完全符合我的要求。
    • 所以在今天早上调查之后,这个脚本没有任何用处——因为添加到已经是模板标签的 LOCAL 上下文不会将它暴露给整个页面模板的 GLOBAL 上下文。仍在寻找解决此问题的答案。
    【解决方案3】:

    有一个应用程序 django-sekizai 就是为了这个

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-08
      • 1970-01-01
      • 2021-02-07
      • 2022-07-07
      • 2015-04-13
      • 1970-01-01
      • 2017-02-12
      相关资源
      最近更新 更多