内置模板事件
Finch 在每次 Jinja 渲染时,都会向模板中注入一组内置变量和辅助函数。这些内容可以通过特殊前缀访问,与你自己通过 addParam() 添加的数据并存。
全局变量
{{ isLocalDebug }} {# 调试模式下运行时为 true #}
{{ data }} {# 通过 rq.addParam() 添加的所有参数组成的 map #}
{{ session }} {# 服务器端会话(session)map #}
{{ $rq }} {# Request 对象 #}
资源辅助方法
{{ assets.js() }} {# 渲染所有通过 rq.addAsset() 添加的 <script> 标签 #}
{{ assets.css() }} {# 渲染所有 <link> 标签 #}
{{ assets.dataJs() }} {# 渲染供 JS 访问的 data 属性 #}
路由和 URL 辅助方法($e)
{{ $e.route }} {# 匹配到的路由的渲染后路径,例如 '/users/42' —— 即匹配此次请求的具体 path/extraPath #}
{{ $e.routePath }} {# 路由的规范完整路径模式,例如 '/users/{id}'(始终基于主 `path`,即便实际匹配的是某个 `extraPath`) #}
{{ $e.routeKey }} {# 路由的 `key`,例如 'users.show' —— 与 $e.route 并不是同一个东西 #}
{{ $e.isKey('root.panel') }} {# 当前路由的 key 是否匹配 #}
{{ $e.hasKey(['root.panel', 'root.form']) }} {# 当前路由的 key 是否是其中之一 #}
{{ $e.routeUrl('key') }} {# 具名路由的 URL #}
{{ $e.routeUrl('users.show', {'id': '42'}) }} {# 带路径参数的 URL #}
{{ $e.routeUrl('search', {}, {'q': 'hello'}) }} {# 带查询参数的 URL #}
{{ $e.uri }} {# 完整请求 URI,以经过百分号编码的字符串形式返回 #}
{{ $e.uriString }} {# 完整请求 URI,未经编码 #}
{{ $e.path }} {# 仅请求路径,以经过百分号编码的字符串形式返回 #}
{{ $e.pathString }} {# 仅请求路径,未经编码 #}
{{ $e.isPath('/example/form') }} {# 当前路径是否匹配 #}
{{ $e.endpoint }} {# 匹配到的端点路径 #}
{{ $e.url('/about') }} {# 根据路径构建绝对 URL #}
{{ $e.urlParam('/users', {'id': '5'}) }} {# 追加查询参数后的 URL #}
{{ $e.urlToLanguage('fa') }} {# 将当前 URL 切换为另一种语言 #}
尽管名字看起来如此,
$e.uri/$e.path实际上是经过百分号编码的字符串,并不是 Dart 的Uri对象,也不是路径段列表——如果需要原始的、未编码的值,请使用$e.uriString/$e.pathString。
Cookie 辅助方法
{{ $e.getCookie('theme', 'light') }} {# 读取一个带默认值的 cookie;此读取始终是明文(未加密)的 #}
Language Helpers
{{ $e.ln }} {# 当前语言代码,例如 'en' #}
{{ $e.langs }} {# 所有已配置语言的列表:[{code, label, contry}] #}
$e.dir 以及 $e.langs 中每个条目里的 label/contry 字段,并不是从语言文件中一个普通的 "dir" 键读取的——它们查找的是专门的翻译键,命名为 language.<code>_dir、language.<code>_label 和 language.<code>_contry(注意:是 contry,不是 country——这是框架本身真实存在的拼写问题,并非本文档的笔误)。如果这些键在你的语言文件中不存在,.tr.write() 会静默地回退,直接返回该键本身,因此 {{ $e.dir }} 实际渲染出来的会是字面文本 language.en_dir,而不是 ltr。
Finch 示例项目自身的语言文件只定义了一个普通的 "dir" 键,并没有定义这些 language.* 键,因此开箱即用时 $e.dir/$e.langs[].label/$e.langs[].contry 都是无法解析的。示例项目自身的布局通过改用 {{ $t('dir') }}(直接查找普通的 "dir" 键)绕开了这个问题——参见 Templates 中的完整示例。你可以自行为每个语言文件添加 language.<code>_dir/_label/_contry 这些键,也可以优先使用 $t('dir') 或你自己的翻译键,而不是 $e.dir 以及 $e.langs 的 label/contry 字段。
工具辅助方法
{{ $e.widgetPath('partials/nav') }} {# 为路径追加所配置的 widget 扩展名,例如 'partials/nav.j2.html' —— 不会自动添加 widgetsPath 前缀 #}
{{ $e.randomString(8) }} {# 生成一个 8 个字符的随机字符串(若省略参数,默认长度为 4) #}
{{ $e.toString(value) }} {# 将任意值转换为字符串 #}
翻译
{{ $t('logo.title') }} {# 翻译一个键 #}
{{ $t('greeting', {'name': user.name}) }} {# 带参数翻译 #}
嵌套数据导航
{{ $n('user/address/city', 'Unknown') }} {# 安全地导航嵌套参数 #}
调试转储
{{ dump(data) }} {# 在浏览器中可视化转储任意变量(仅调试模式) #}
自定义本地事件
在 app.dart 中使用 Request.localEvents 定义你自己的全局函数:
Request.localEvents.addAll({
'currentYear': () => DateTime.now().year,
'appName': () => 'My App',
});
在模板中使用 $l. 前缀访问它们:
<footer>© {{ $l.currentYear() }} {{ $l.appName() }}</footer>