模板

模板语法

变量

你可以像下面这样显示一个变量:

Your payoff is {{ player.payoff }}.

下面的变量在模板中均可用:

  • player: 当前正在浏览页面的玩家
  • group: 当前玩家所属的小组
  • subsession: 当前玩家所属的子会话
  • participant: 当前玩家所属的参与人
  • session: 当前会话
  • C
  • 任何你使用 vars_for_template() 传递的变量。

条件(“if”)

注解

oTree 3.x 在模板中使用两种不同的标签:{{ }}{% %}。但从oTree 5开始,你可以忘了 {% %} 并在任何你想使用的地方只用 {{ }} 。旧格式仍然可用。

使用‘else’:

Complex example:

循环(“for”)

{{ for item in some_list }}
    {{ item }}
{{ endfor }}

获取字典中的元素

在Python代码中使用 my_dict['foo'] 的地方,在模板中应当使用 {{ my_dict.foo }}

注释

{# this is a comment #}

{#
    this is a
    multiline comment
#}

不正确的使用

模板语言仅仅是为了显示值。你不能在其中做数学运算 (+, *, /, -) 或者修改数字,列表,字符串等等。想要做这些事情,应当使用 vars_for_template()

模板是如何工作的:一个例子

oTree模板是两种语言的混合:

  • HTML (使用尖角括号如 <this></this>。)
  • 模板标签 (使用大括号如 {{ this }}{{ this }})

在这个例子中,假定你的模板如下:

<p>Your payoff this round was {{ player.payoff }}.</p>

{{ if subsession.round_number > 1 }}
    <p>
        Your payoff in the previous round was {{ last_round_payoff }}.
    </p>
{{ endif }}

{{ next_button }}

步骤1:oTree扫描模板标签,生成HTML(亦称“服务器端”)

oTree使用变量当前的值将模板标签转换为纯HTML,像下面这样:

<p>Your payoff this round was $10.</p>

    <p>
        Your payoff in the previous round was $5.
    </p>

<button class="otree-btn-next btn btn-primary">Next</button>

步骤2:浏览器扫描HTML标签,生成web页面(亦称“浏览器端”)

oTree服务器将HTML发送给用户的电脑,用户的web浏览器可以解析这些代码并将其显示为格式化的web页面:

_images/template-example.png

注意浏览器永远不会收到模板标签。

要点

如果页面没有如期望正常工作,你可以分开来看上面两步中哪一步出错了。在浏览器中,右键单击并“查看源代码”。(注意:“查看源代码”在分离屏幕模式下可能无法正常工作。)

你可以看到生成的纯HTML(与JavaScript和CSS)。

  • 如果HTML代码看起来不是所期望的,那么可能服务器端出现了某种问题。可在 vars_for_template 或者模板标签中寻找错误。
  • 如果生成的HTML代码没有任何错误,那么可能你使用了错误的HTML(或者JavaScript)语法。试着将HTML有问题的部分粘贴回模板中,去掉模板标签,编辑它直到输出正常。再尝试将模板标签加回去,使得页面重新成为动态的。

图片(静态文件)

在项目中包含图片,视频,第三方JS/CSS库或者其他静态文件的最简单的方法是将它们在线存放,例如使用Dropbox,Imgur,YouTube等等。

然后,将URL包含在 <img> 或 <video> 标签内放在模板中,例如:

<img src="https://i.imgur.com/gM5yeyS.jpg" width="500px" />

你也可以直接将图片存放在你的项目中。(但注意文件较大会影响性能)。oTree Studio有一个图片上传工具。(如果你使用文本编辑器,参考 这里。)将图片存储在项目中后,你可以像下面这样显示它:

<img src="{{ static 'folder_name/puppy.jpg' }}"/>

动态图片

如果你需要根据上下文显示不同的图片(比如每一轮显示不同的图片),那么你可以在 vars_for_template 中构建并将其传递给模板,例如:

@staticmethod
def vars_for_template(player):
    return dict(
        image_path='my_app/{}.png'.format(player.round_number)
    )

然后在模板中使用:

<img src="{{ static image_path }}"/>

可包含的模板

如果你将相同的内容在多个模板之间复制粘贴,更好的方案是创建一个可包含的模板并使用 {{ include_sibling }} 复用模板。

举例来说,如果在你的游戏中游戏说明需要在每一个页面上重复出现,那么就可以创建一个模板,叫做 instructions.html,并将说明放入其中,例如:

<div class="card bg-light">
    <div class="card-body">

    <h3>
        Instructions
    </h3>
    <p>
        These are the instructions for the game....
    </p>
    </div>
</div>

Then use {{ include_sibling 'instructions.html' }} to insert it anywhere you want.

注解

{{ include_sibling }} is a new alternative to {{ include }}. The advantage is that you can omit the name of the app: {{ include_sibling 'xyz.html' }} instead of {{ include 'my_app/xyz.html' }}. However, if the includable template is in a different folder, you must use {{ include }}.

JavaScript 与 CSS

将JavaScript/CSS代码放在何处

你可以使用常见的 <script></script><style></style> 标签将JavaScript与CSS放在你模板的任意位置。

如果你有很多脚本/样式,你可以将它们放在 content 之外独立的部分: scripts and styles 中。这并非强制的要求,但这样做会使你的代码更有条理并确保页面按照顺序加载(CSS,然后是页面内容,然后是JavaScript)。

定制主题

如果你想要定制oTree元素的外观,下表列出了CSS选择器:

元素 CSS/jQuery 选择器
页面主体 .otree-body
页面标题 .otree-title
等待页面(整个对话框) .otree-wait-page
等待页面对话框标题 .otree-wait-page__title (注意: __, 而非 _)
等待页面对话框主体 .otree-wait-page__body
计时器 .otree-timer
下一步按钮 .otree-btn-next
表单错误警告 .otree-form-errors

举例来说,想要改变页面宽度,将CSS在基模板中放置如下:

<style>
    .otree-body {
        max-width:800px
    }
</style>

获取更多信息,可在浏览器中右键单击你想要修改的元素并选择“审查元素”。然后你可以导航到不同元素并试着改变它们的样式:

_images/dom-inspector.png

尽可能使用上面给出的官方选择器。不要使用任何以 _otree 开头或者基于Bootstrap类的选择器,如 btn-primarycard,因为它们是不稳定的。

从Python向JavaScript传递数据(js_vars)

为了在模板中向JavaScript代码传递数据,在你的页面中定义一个 js_vars 方法,例如:

@staticmethod
def js_vars(player):
    return dict(
        payoff=player.payoff,
    )

在模板中,你就可以像下面这样引用这些变量:

<script>
    let x = js_vars.payoff;
    // etc...
</script>

Bootstrap

oTree使用了 Bootstrap,一个流行的用于定制网站用户界面的库。

如果你想要 定制样式,或者 特定组件 如表格,警告,进度条,标签,等等,你可以使用此库。你甚至可以让你的页面变得动态,通过使用组件如 popoversmodals, 和 collapsible text

使用Bootstrap,通常需要在HTML元素中添加一个 class= 属性。

举例来说,下面得HTML会创建一个“Success” 警告:

<div class="alert alert-success">Great job!</div>

移动设备

Bootstrap会在手机或平板上试着显示一个“移动端友好”的版本。

Best way to test on mobile is to use Heroku. otree zipserver doesn’t accept a ‘port’ argument. Also, devserver/zipserver seem to have issues with shutdown/reloading and freeing up the port.

图表

你可以使用任何HTML/JavaScript库来为你的应用添加图表。HighCharts 是一个不错的选择,它可以用来画饼状图,折线图,直方图,时间序列等等。

首先,引入HighCharts JavaScript:

<script src="https://code.highcharts.com/highcharts.js"></script>

在HighCharts demo site 寻找你想要的图表类型。然后点击”edit in JSFiddle”将其编辑成你想要的样子,使用硬编码数据。

然后,复制粘贴JS与HTML到你的模板中,并加载页面。如果你没有看到你的图表,可能是因为JS代码试图插入图表的那一部分HTML缺少了 <div> 标签。

一旦你的图表加载正常,你就可以将硬编码的数据替换为 seriescategories 这样动态生成的变量。

例如,将下面的代码:

series: [{
    name: 'Tokyo',
    data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
}, {
    name: 'New York',
    data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]
}]

改为:

series: js_vars.highcharts_series

…此处 highcharts_series 是你在 js_vars 中定义的变量。

如果你的图表没有加载,在浏览器中单击“查看源码”检查是否是动态生成的数据出现了问题。

杂项

你可以使用 to2to1, 或 to0 过滤器来对数字取整。例如: {{ 0.1234|to2}} 的输出是 0.12。