88

假设我有一个 Python 变量:

list_of_items = ['1','2','3','4','5']

我通过呈现 HTML 将其传递给 Jinja,并且我在 JavaScript 中还有一个名为somefunction(variable). 我正在尝试通过list_of_items. 我试过这样的事情:

{% for item in list_of_items %}
<span onclick="somefunction({{item}})">{{item}}</span><br>
{% endfor %}

是否可以将列表从 Python 传递到 JavaScript,或者我应该在循环中一个一个地传递列表中的每个项目?我怎样才能做到这一点?

4

6 回答 6

127

要将一些上下文数据传递给 javascript 代码,您必须以 javascript(即 JSON)“理解”的方式对其进行序列化。您还需要使用safeJinja 过滤器将其标记为安全,以防止您的数据被 htmlescaped。

您可以通过执行以下操作来实现此目的:

风景

import json

@app.route('/')
def my_view():
    data = [1, 'foo']
    return render_template('index.html', data=json.dumps(data))

模板

<script type="text/javascript">
    function test_func(data) {
        console.log(data);
    }
    test_func({{ data|safe }})
</script>

编辑 - 确切答案

因此,要准确实现您想要的(遍历项目列表,并将它们传递给 javascript 函数),您需要分别序列化列表中的每个项目。您的代码将如下所示:

风景

import json

@app.route('/')
def my_view():
    data = [1, "foo"]
    return render_template('index.html', data=map(json.dumps, data))

模板

{% for item in data %}
    <span onclick=someFunction({{ item|safe }});>{{ item }}</span>
{% endfor %}

编辑 2

在我的示例中,我使用Flask,我不知道您使用的是什么框架,但您明白了,您只需使其适合您使用的框架。

编辑 3(安全警告)

永远不要对用户提供的数据执行此操作,仅对受信任的数据执行此操作!

否则,您会将您的应用程序暴露给 XSS 漏洞!

于 2013-03-10T12:11:24.113 回答
37

我在使用 Flask 时遇到了类似的问题,但我不必求助于 JSON。我刚刚通过了一个列表letters = ['a','b','c']render_template('show_entries.html', letters=letters)并设置

var letters = {{ letters|safe }}

在我的 javascript 代码中。Jinja2 替换{{ letters }}['a','b','c'],javascript 将其解释为字符串数组。

于 2014-03-03T21:20:51.943 回答
19

你可以用 Jinja 的tojson过滤器来做到这一点,它

将结构转储到 JSON,以便<script>在 HTML 中任何位置的标签 [和] 中使用安全,但双引号属性除外。

例如,在您的 Python 中,编写:

some_template.render(list_of_items=list_of_items)

...或者,在 Flask 端点的上下文中:

return render_template('your_template.html', list_of_items=list_of_items)

然后在你的模板中,写下:

{% for item in list_of_items %}
<span onclick='somefunction({{item | tojson}})'>{{item}}</span><br>
{% endfor %}

(请注意,该onclick属性是引号。这是必要的,因为在其输出中|tojson转义'字符而不是"字符,这意味着它可以安全地用于单引号 HTML 属性,但不能用于双引号。)

或者,要使用list_of_items内联脚本而不是 HTML 属性,请编写以下代码:

<script>
const jsArrayOfItems = {{list_of_items | tojson}};
// ... do something with jsArrayOfItems in JavaScript ...
</script>

不要json.dumps在 Python 代码中使用 JSON 编码变量并将生成的 JSON 文本传递给模板。这将对某些字符串值产生不正确的输出,并且如果您尝试对用户提供的值进行编码,则会将您暴露给 XSS。这是因为 Python 的内置json.dumps不转义字符,如<and >(需要转义以安全地将模板值转换为 inline <script>s,如https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for中所述-contents-of-script-elements)或单引号(需要转义以安全地将模板值转换为单引号 HTML 属性)。

如果您使用的是 Flask,请注意 Flask 会注入自定义tojson过滤器,而不是使用 Jinja 的版本。但是,上面写的所有内容仍然适用。这两个版本的行为几乎相同;Flask 只允许在 Jinja 的版本中不可用的一些特定于应用程序的配置。

于 2018-12-27T23:54:26.913 回答
3

为了添加所选答案,我一直在测试一个使用 jinja2 和烧瓶的新选项:

@app.route('/')
def my_view():
    data = [1, 2, 3, 4, 5]
    return render_template('index.html', data=data)

模板:

<script>
    console.log( {{ data | tojson }} )
</script>

渲染模板的输出:

<script>
    console.log( [1, 2, 3, 4] )
</script>

safe可以添加,但也想避免{{ data | tojson | safe }}html 转义,但它也可以在没有的情况下工作。

于 2018-04-18T16:14:10.807 回答
2

我可以向您建议一种面向 javascript 的方法,这使得在您的项目中使用 javascript 文件变得容易。

在您的 jinja 模板文件中创建一个 javascript 部分,并将您要在 javascript 文件中使用的所有变量放在一个窗口对象中:

开始.html

...
{% block scripts %}
<script type="text/javascript">
window.appConfig = {
    debug: {% if env == 'development' %}true{% else %}false{% endif %},
    facebook_app_id: {{ facebook_app_id }},
    accountkit_api_version: '{{ accountkit_api_version }}',
    csrf_token: '{{ csrf_token }}'
}
</script>
<script type="text/javascript" src="{{ url_for('static', filename='app.js') }}"></script>
{% endblock %}

Jinja 将替换值,我们的 appConfig 对象将可以从我们的其他脚本文件中访问:

应用程序.js

var AccountKit_OnInteractive = function(){
    AccountKit.init({
        appId: appConfig.facebook_app_id,
        debug: appConfig.debug,
        state: appConfig.csrf_token,
        version: appConfig.accountkit_api_version
    })
}

我用这种方式将 javascript 代码从 html 文档中分离出来,这种方式更易于管理和 seo 友好。

于 2017-01-07T11:58:13.987 回答
-1

制作一些不可见的 HTML 标签,如<label>, <p>, <input>etc. 并命名它的 id,类名是一个模式,以便您以后可以检索它。

让您有两个相同长度的列表 maintenance_next[] 和 maintenance_block_time[],并且您想使用烧瓶将这两个列表的数据传递给 javascript。因此,您获取一些不可见的标签标签并将其标签名称设置为列表索引的模式,并将其类名称设置为索引处的值。

{% for i in range(maintenance_next|length): %}
<label id="maintenance_next_{{i}}" name="{{maintenance_next[i]}}" style="display: none;"></label>
<label id="maintenance_block_time_{{i}}" name="{{maintenance_block_time[i]}}" style="display: none;"></label>
{% endfor%}

现在您可以使用如下的一些 javascript 操作检索 javascript 中的数据 -

<script>
var total_len = {{ total_len }};
 
for (var i = 0; i < total_len; i++) {
    var tm1 = document.getElementById("maintenance_next_" + i).getAttribute("name");
    var tm2 = document.getElementById("maintenance_block_time_" + i).getAttribute("name");
    
    //Do what you need to do with tm1 and tm2.
    
    console.log(tm1);
    console.log(tm2);
}
</script>

于 2019-12-09T05:22:39.953 回答