【问题标题】:Passing context variable from template to JavaScript file将上下文变量从模板传递到 JavaScript 文件
【发布时间】:2021-09-22 20:19:18
【问题描述】:

这个线程here 讨论了在模板中使用内联 JavaScript 中的变量。如果我有单独的包含脚本的 .js 文件,则位于 static 文件夹中,例如:

utils.js

const createButton = (buttonCount) => {
    containerId = "myContainerId"
    container = document.getElementById(containerId)
    for (var i = 0; i < buttonCount; i++) {}
        newButton = document.createElement("button")
        newButton.value = "Test"
        newButton.id = "testButton" + i
        container.appendChild(newButton)
    }
}

createButton(buttonCount)

mytemplate.html

{% extends "base.html" %}
{% load static %}

{% block title %}Testpage{% endblock %}


{% block content-main %}
  <link href="{% static "css/mycss.css" %}" rel="stylesheet">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.4.0/css/bulma.css" /> 

  <div id="myContainerId"></div>

  <script src="{% static 'js/utils.js' %}"> </script>

{% endblock %}

如果我有一个变量 buttonCount 通过视图函数的上下文传递到此模板,我如何将它传递到 utils.js 文件以由函数 createButton() 调用?

views.py

def button_view(request):
    ...
    buttonCount = 5
    return render(request, 'mytemplate.html', {'buttonCount': buttonCount})

【问题讨论】:

    标签: javascript django django-templates


    【解决方案1】:

    有几种方法:

    • 使用输入字段
    
        <input id="buttonCount" value = "{{buttonCount}}" style="display:none;">
    
    

    然后读取 utils.js 中 id= buttonCount 的元素的值。

    • 内联脚本 **不建议,改用 Document.onload。

       <script>
       set_button_count({{buttonCount}});
       </script>
      

    但是当您的 utils.js 尚未加载时,这会产生问题。

    • document.onload 将脚本源放在&lt;head&gt;&lt;/head&gt;
    
        <script src="{% static 'js/utils.js' %}" defer> </script>
        <script>
        document.addEventListener('onload',function(
        {set_button_count({{buttonCount}});
        })
        </script>
    
    
    1. set_button_count() 将放在 utils.js 中
    2. Defer 将要求浏览器仅在 utils.js 时触发文档加载 已完成,将在文档完成后获取并加载 已加载。

    警告:内联脚本将与严格的 CSP(内容安全策略)一起使用。任何内联脚本都可以将 src 指定为 nonce。 CSP 可以在 apache 或 Nginx 上的服务器端完成,它们是非常常见的 Web 服务器/反向代理,或者如果您无法控制,您也可以在 HTML 中提及相同的内容。

    
    <meta http-equiv="Content-Security-Policy" 
            content="default-src 'self';
            script-src 'self' 'nonce-{{nonce}}';">
    
    

    这个nonce 可以像这样生成:

    
        import random,base64
        
        def usersession_processor(request):
            user = request.user
            unbaked_nonce = '%32x' % random.getrandbits(16*8)
            unbaked_nonce = unbaked_nonce.encode('utf-8')
            baked_nonce = base64.b64encode(unbaked_nonce)
            baked_nonce = baked_nonce.decode('utf-8')
    
    

    然后&lt;script src="{{nonce}}"&gt;&lt;/script&gt; 可以用于安全内联。

    【讨论】:

    • 谢谢。看来我只能在.js 文件中声明一个函数,但不能在那里调用它。我必须在模板中内联调用它,并将变量作为参数传递,就像上面的选项 3 一样。此外,似乎只要我在调用内联函数之前声明脚本源,它就可以工作&lt;script src="{% static 'js/utils.js' %}"&gt; &lt;/script&gt; &lt;script&gt; document.addEventListener('onload', createButton({{buttonCount}})) &lt;/script&gt;
    • 它在开发中有效,但在产品中有时与开发中的工作方式不同。我建议将 defer 和 EventListener 一起使用。第一次以随机顺序加载脚本时遇到了很多困难,因为在此之前运行了不同的大小和内联脚本。
    【解决方案2】:

    我不认为这是推荐的,但如果你使用 django 模板上下文,你可以这样做。将脚本放在页面底部,并将 buttoncount 作为 Django 模板语言变量包含在内。不过,我认为不建议将 Django 模板变量与 javascript 混合使用。

    你可以在你的'base.html'文件中放一个新的块,在body标签的底部,像这样:

    {% block inline_javascript %}
    {% enblock inline_javascript %}
    

    然后在您希望函数在其上运行的页面内,将脚本放在该页面底部的“块内容”之外的相同标签内,例如:

    {% block inline_javascript %}
        <script>
            const createButton = ({{ buttonCount }}) => {
                containerId = "myContainerId"
                container = document.getElementById(containerId)
                for (var i = 0; i < {{ buttonCount }}; i++) {}
                    newButton = document.createElement("button")
                    newButton.value = "Test"
                    newButton.id = "testButton" + i
                    container.appendChild(newButton)
                }
            }
        </script>
    {% enblock inline_javascript %}
    

    【讨论】:

    • 谢谢。似乎将变量传递到单独的 .js 文件中,其中调用 JavaScript 函数是不可能的。函数的调用和变量的传递必须在模板中内联完成。
    • 是的,但我可能会考虑使用 name 属性设置为按钮计数变量的隐藏输入,然后使用内联 javascript 从中提取值,而不是将变量放在 JS 中
    • 这是为了避免潜在的“注入”吗?如果是这样,谢谢,这是有道理的。
    猜你喜欢
    • 2014-02-09
    • 2011-10-23
    • 2013-12-16
    • 1970-01-01
    • 2014-09-05
    • 2012-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多