过滤器与助手
过滤器对插值值做变换,| 分隔、可链式,name 或 name:arg 形式(arg 支持 "带引号字面量",内部可含中文与 |)。
html
{{ name | upper }}
{{ bio | default:"暂无" }}
{{ title | lower | capitalize }}内置值过滤器
| 过滤器 | 作用 |
|---|---|
upper | ASCII 大写(多字节字符原样) |
lower | ASCII 小写 |
capitalize | 首字母(ASCII)大写 |
default:"x" | 值为空值/空串/空列表时取 x,否则原值 |
length | 列表→元素数;字符串→Unicode 字符数 |
json | 把值序列化为 JSON 字符串(终结,见下) |
upper/lower/capitalize只做 ASCII 大小写折叠,以规避 Unicode 大小写映射的复杂度与歧义;多字节字符保持原样。
终结转义过滤器
以下过滤器决定最终输出转义,出现在链末位时会跳过默认 HTML 转义:
| 过滤器 | 作用 | 典型上下文 |
|---|---|---|
raw | 不转义(等价 {{& x }}) | 已可信的 HTML 片段 |
html | HTML 实体转义 | 元素内容/属性(默认即此) |
js | JS 字符串字面量转义(含 </script> 中和) | <script> 内嵌 |
url | RFC 3986 组件百分号编码 | URL 查询参数 |
attr | HTML 属性值转义(含反引号) | 属性上下文 |
html
<a href="/s?q={{ query | url }}">搜索</a>
<script>var name = "{{ name | js }}";</script>
<div title="{{ tip | attr }}">…</div>求值与转义顺序
- 解析
path取值; - 依次应用链中的值过滤器(
upper/default/…); - 转标量字符串;
- 若链末位是终结转义过滤器(
raw/html/js/url/attr/json)→ 按它输出,不再自动 HTML 转义;否则若是默认{{ }}→ HTML 转义,{{& }}/{{{ }}}→ 原样。
因此 {{ x | upper }} 先大写再 HTML 转义;{{ x | raw }} ≡ {{& x }};{{ x | js }} 输出 JS 转义且不被二次 HTML 转义。未注册的过滤器名被静默跳过(不改变值,链继续)。
自定义助手(registerFilter)
用 engine.registerFilter(name, fn) 注册助手,签名 (TemplateValue, ?String) -> TemplateValue:
cangjie
// 应用启动期(如组件 onReady / @PostConstruct)注册自定义助手
// 加感叹号:{{ word | exclaim }}
engine.registerFilter("exclaim", {v: TemplateValue, _: ?String =>
TStr(scalarString(v) + "!")
})
// 带参数:{{ label | prefix:"[TODO] " }}
engine.registerFilter("prefix", {v: TemplateValue, arg: ?String =>
let p = arg ?? ""
TStr(p + scalarString(v))
})html
{{ word | exclaim }}
{{ label | prefix:"[TODO] " }}同名可覆盖内置过滤器。
安全说明
- 默认插值
{{ x }}始终 HTML 转义(含反引号`),覆盖元素内容与带引号/无引号属性上下文。 - 上下文匹配:进入 JS 用
| js、URL 参数用| url、属性用| attr;json过滤器已中和< > & /,可安全内联进<script>(防</script>断标签)。 raw/{{& }}/{{{ }}}绕过转义,仅用于可信内容,切勿直接输出用户输入。