amis Tpl 模板组件完全指南:从变量插值到事件派发
2026/9/13 20:35:55 网站建设 项目流程

amis Tpl 模板组件完全指南:从变量插值到事件派发

【免费下载链接】amis前端低代码框架,通过 JSON 配置就能生成各种页面。项目地址: https://gitcode.com/GitHub_Trending/am/amis

Tpl 是 amis 低代码框架中用于输出模板文本/HTML的通用组件,通过type: "tpl"配合tpl属性即可把数据域中的变量渲染进页面,是列表、表格、卡片等场景中最常使用的展示型组件。读完本文你将掌握 Tpl 的完整配置属性、数据映射与过滤器用法、JavaScript 模板引擎语法,以及基于onEvent的点击/悬停事件派发方案。

一、Tpl 是什么

在 amis 中,绝大多数文案类展示(如表格单元格、卡片标题、面包屑分隔符、提示内容等)都可以由一个 Tpl 完成。官方文档对其定位的描述非常简短:"输出模板的常用组件"。也就是说,Tpl 是 amis 模板能力在前端组件层的统一出口,底层由 packages/amis/src/renderers/Tpl.tsx 实现,并通过@Renderer({type: 'tpl', alias: ['html']})注册(见 Tpl.tsx),因此它还有一个别名html,即{"type": "html", "html": "..."}{"type": "tpl", "tpl": "..."}等价。

从源码结构看,Tpl 组件支持tplhtmltextraw四种内容来源,并内置inline: true(默认以span渲染、内联显示)与空值placeholder(默认空字符串)两个默认属性(见 Tpl.tsx),这为后续各类属性讲解提供了实现依据。

二、基本用法:让静态页面"活"起来

在数据域中放置变量,然后用${变量名}在模板中引用:

{ "data": { "text": "World!" }, "type": "page", "body": { "type": "tpl", "tpl": "Hello ${text}" } }

页面输出为Hello World!。这里type固定为tpltpl即模板字符串。完整的模板语法体系在模板文档中有详细说明,本文后续会结合 Tpl 逐一展开。

关于变量取值,需要了解 amis 的数据映射${xxx}$xxx)机制,它的完整规范记录在数据映射中,核心能力包括:

  • 链式取值${company.name}可逐层访问嵌套对象;
  • 转义输出:想输出字面量${xxx},需在$前加反斜杠写成\${xxx}
  • 命名空间取值(1.1.6 起):${window:document.title}${ls:key}${ss:key}${cookie:key}分别读取全局变量、localStorage、sessionStorage 与 cookies;
  • 过滤器${xxx | filter1 | filter2}支持串联处理。

这些取值能力在 Tpl 中的实际解析入口是 amis-core 的filter/asyncFilter函数(packages/amis-core/src/utils/tpl.ts),它按注册顺序依次让各模板引擎"认领"字符串,命中即编译。

三、渲染 HTML 与安全转义

Tpl 输出的是 HTML(最终通过dangerouslySetInnerHTML注入,见 Tpl.tsx),因此模板中可以内嵌标签:

{ "data": { "text": "World!" }, "type": "page", "body": "<h1>Hello</h1> <span>${text}</span>" }

默认情况下,变量内容会经过html 转义(内置引擎的默认过滤器为| html,见 packages/amis-core/src/utils/tpl-builtin.ts),所以当变量本身携带 HTML 时需要用raw过滤器关闭转义:

{ "data": { "text": "<b>World!</b>" }, "type": "page", "body": "<h1>Hello</h1> <span>${text|raw}</span>" }

安全提醒raw意味着不经过滤直接输出,动态渲染用户可控内容极易引发XSS攻击。官方文档明确警告:使用raw时请确保变量内容可信,永远不要渲染用户填写的内容(见数据映射的 raw 小节)。

四、Tpl 属性表详解

Tpl 的核心属性如下(对应文档属性表):

属性名类型默认值说明
typestring"tpl"指定为 Tpl 组件,亦可写"html"(源码中的别名)
classNamestring外层 DOM 节点的类名
tpl模板配置模板字符串/模板引擎语法
showNativeTitleboolean是否把文本内容设置到外层 DOM 的title属性(鼠标悬停显示)

className:定制外层样式

className会通过 classnames 库合并到组件根节点上(Tpl.tsx)。常见用法如给单元格文本加间距或颜色类:

{ "type": "tpl", "tpl": "重要提示", "className": "text-danger m-l-sm" }

showNativeTitle:悬停显示全文

开启后,Tpl 会把渲染出的文本内容写入外层 DOM 的title属性,鼠标悬停时浏览器会弹出原生提示。源码中使用DOMParser解析内容并提取纯文本(剔除 HTML 标签)作为 title(见 Tpl.tsx),因此即使模板包含富文本,title 也只会显示纯文本:

{ "type": "tpl", "tpl": "这是一段很长的说明文字", "showNativeTitle": true }

源码中未被文档列出的扩展属性

从 AMISTplSchema 类型定义看,Tpl 还支持若干文档属性表未提及、但实际可用的能力,可视为对属性表的补充:

  • html/text/raw:除tpl外的三种内容源,优先级为raw > html > tpl > text(见 Tpl.tsx)。其中text会强制对结果做escapeHtml转义,适合纯文本展示;
  • inline:是否内联显示,默认true,为false时外层渲染为div
  • wrapperComponent:自定义外层标签;
  • style:支持样式对象(且支持用数据映射动态计算,经buildStyle处理);
  • maxLine:文本超出指定行数时截断显示(设置WebkitLineClamp);
  • badge:角标配置;
  • placeholder:值为空时的占位内容(默认空字符串);
  • value:不写模板时,直接渲染传入的 value(对象会自动JSON.stringify)。

例如一个带行数截断的纯文本 Tpl:

{ "type": "tpl", "text": "${intro}", "maxLine": 2 }

五、模板能力纵深:Tpl 背后的两套模板引擎

Tpl 的tpl属性支持两种语法体系,它们由 amis-core 的模板引擎注册机制统一调度:filter会遍历已注册引擎,命中test即使用对应引擎编译(packages/amis-core/src/utils/tpl.ts),目前默认注册了builtinlodash两个引擎(tpl.ts)。两种语法不能混用,完整说明见模板文档的"注意事项"章节。

1. 内置模板字符串(默认引擎,builtin)

  • ${xxx}从数据域取值,支持链式与过滤器;
  • 识别规则:检测$字符且其后不是引号/空格、且未被\转义(见 tpl-builtin.ts);
  • 变量缺失或为空时默认显示空,可用| default过滤器兜底。

2. 表达式语法(1.5.0+)

${xxx}内可以直接写三元表达式或调用公式函数:

{ "type": "tpl", "tpl": "${xxx == 1 ? 'One' : 'Others'}" }

表达式由 amis-formula 的parse/evaluate求值(见 packages/amis-core/src/utils/tpl.ts),完整的表达式能力见表达式文档。

3. JavaScript 模板引擎(lodash template)

当模板中出现<%时,字符串会交给 lodash 引擎,语法与 ejs 类似:<%= 输出 %><% JS 语句 %>注意此时取变量要用data.xxx,因为 lodash 引擎把数据域作为模板作用域(variable: 'data',见 packages/amis-core/src/utils/tpl-lodash.ts):

{ "type": "page", "data": { "user": "no one", "items": ["A", "B", "C"] }, "body": [ { "type": "tpl", "tpl": "User: <%- data.user %>" }, { "type": "divider" }, { "type": "tpl", "tpl": "<% if (data.items && data.items.length) { %>Array: <% data.items.forEach(function(item) { %> <span class='label label-default'><%- item %></span> <% });} %>" } ] }

引擎内部通过template(str, {imports, variable: 'data', interpolate: /<%=([\s\S]+?)%>/g})编译,其中刻意禁用了 lodash 默认的${xxx}插值语法,避免与内置模板字符串冲突(tpl-lodash.ts)。

lodash 引擎额外注入了以下工具方法(见 tpl-lodash.ts):

方法说明
formatDate(value, format='LLL', inputFormat='')格式化时间,format 遵循 moment 语法
formatTimeStamp(value, format='LLL')时间戳转格式化字符串(内部即 date 过滤器)
formatNumber(number)数字千分位格式化(内部即 number 过滤器)
countDown(value)倒计时,显示距指定时间戳还剩多少天,已过期显示"已结束"
momentmoment 对象本身也可直接用

同时,模板字符串章节的全部过滤器(如datenumber)在 lodash 引擎中也能以函数形式调用,例如<%- date(data.xxx, 'YYYY-MM-DD') %>

两种语法不可交叉混用

{ "type": "tpl", "tpl": "${data.xxx === 'a'}" }

上面是错误写法——内置引擎中应直接写${xxx === 'a'}而不是data.xxx;反之在<% %>中则必须用data.xxx取值。两种取值风格混用是初学者最容易踩的坑。

六、数据映射与常用过滤器实战

Tpl 模板中频繁用到的过滤器(完整清单见数据映射的"过滤器"章节),以下为高频实用的几个:

{ "type": "page", "data": { "html": "<div>这是一段<code>html</code></div>", "price": 233333333, "now": 1586865590, "value": "", "array": ["a", "b", "c"] }, "body": [ { "type": "tpl", "tpl": "html is: ${html|raw}" }, { "type": "tpl", "tpl": "price is ${price|number}" }, { "type": "tpl", "tpl": "now is ${now|date:YYYY-MM-DD}" }, { "type": "tpl", "tpl": "value is ${value|default:-}" }, { "type": "tpl", "tpl": "array is ${array|join}" } ] }
  • raw:输出原始 HTML(注意 XSS 风险);
  • html:显式按 HTML 显示(变量默认即走 html 转义);
  • json[:tabSize]:对象格式化为 JSON 字符串,如${info|json:4}
  • toJson:JSON 字符串转对象;
  • date[:format][:inputFormat]:时间格式化,默认输出LLL(本地化格式),默认按秒时间戳X解析;毫秒需指定x参数中的:需用\转义,如${now|date:LLL:YYYY/MM/DD HH\:mm\:ss}
  • number:千分位;
  • percent[:decimals]:转百分比,默认 0 位小数;
  • round[:decimals]:四舍五入,默认保留 2 位;
  • truncate[:length][:mask]:超长截断,默认 200 字符、省略号...
  • default[:defaultValue]:空值兜底;
  • split[:delimiter]/join[:separator]:字符串与数组互转;
  • fromNow:相对时间(1.4.0+)。

过滤器支持串联,例如 "上个月第一天" 的经典写法:

{ "type": "page", "body": "上个月第一天是:${_|now|dateModify:subtract:1:month|dateModify:startOf:month|date:YYYY-MM-DD HH\\:mm\\:ss}" }

1.5.0 起官方更推荐函数调用式写法,如${html(xxx)}替代${xxx|html},详见表达式文档中的新表达式语法。

七、事件派发:click / mouseenter / mouseleave

2.5.3版本开始,Tpl 会对外派发以下事件(见事件表),可以通过onEvent监听,并通过actions配置执行动作;事件数据用${事件参数名}${event.data.[事件参数名]}获取,完整的事件动作机制见事件动作:

事件名称事件参数说明
click-点击时触发
mouseenter-鼠标移入时触发
mouseleave-鼠标移出时触发

三个事件在源码中分别对应onClickonMouseEnteronMouseLeave处理函数,统一调用dispatchEvent(e, data)派发(见 Tpl.tsx),因此事件上下文里可通过event.context.nativeEvent拿到原生鼠标事件对象。

click 示例

{ "type": "tpl", "tpl": "Hello", "onEvent": { "click": { "actions": [ { "actionType": "toast", "args": { "msgType": "info", "msg": "${event.context.nativeEvent.type}" } } ] } } }

点击文本后弹出 toast,内容为原生事件类型click

mouseenter 示例

{ "type": "tpl", "tpl": "Hello", "onEvent": { "mouseenter": { "actions": [ { "actionType": "toast", "args": { "msgType": "info", "msg": "${event.context.nativeEvent.type}" } } ] } } }

mouseleave 示例

{ "type": "tpl", "tpl": "Hello", "onEvent": { "mouseleave": { "actions": [ { "actionType": "toast", "args": { "msgType": "info", "msg": "${event.context.nativeEvent.type}" } } ] } } }

三个事件常组合使用,例如"移入时高亮、移出时还原、点击时跳转"的交互卡片;actions也支持reloadsetValueajaxdialoglink等多种动作类型,均可在事件动作文档中查阅。

八、实现原理与源码路径速查

梳理 Tpl 的完整调用链,便于读者深入源码:

  1. 注册TplRenderer通过@Renderer({type: 'tpl', alias: ['html']})注册,见 packages/amis/src/renderers/Tpl.tsx;
  2. 内容解析:组件根据raw/html/tpl/text的优先级选择模板源,调用filter(同步)或asyncFilter(异步,支持异步表达式)编译,见 Tpl.tsx;
  3. 引擎调度filter遍历已注册引擎,见 packages/amis-core/src/utils/tpl.ts,内置引擎注册于 tpl.ts;
  4. 内置引擎:负责${xxx}模板字符串与过滤器,实现在 packages/amis-core/src/utils/tpl-builtin.ts;
  5. lodash 引擎:负责<% %>语法,实现在 packages/amis-core/src/utils/tpl-lodash.ts;
  6. 输出:编译结果经env.filterHtml过滤后通过dangerouslySetInnerHTML注入(见 Tpl.tsx),并支持setThemeClassName主题类名与CustomStyle自定义样式注入。

组件在仓库中的使用与测试覆盖非常广泛,可作为参考实践:如 packages/amis/tests/renderers/Each.test.tsx 展示了 Tpl 在循环中的<%= data.item %>用法,packages/amis/tests/renderers/Carousel.test.tsx 展示了 Tpl 输出背景图样式的写法,packages/amis/tests/renderers/AMISRender.test.tsx 则验证了最基础的type: 'tpl'渲染。

九、常见问题小结

  • 模板不生效:确认tpl值是否为字符串,且${}<% %>未混用;
  • HTML 被转义显示为源码:变量内容需要原样输出时用| raw,但要评估 XSS 风险;
  • 时间格式不对:先确认数据是秒(X,默认)还是毫秒(x),再设置inputFormat
  • 悬停不显示 title:检查showNativeTitle是否开启,且注意 title 内容为纯文本(HTML 标签会被剥离);
  • lodash 模板中取不到值<%= %>内必须用data.xxx,而不是${xxx}
  • 事件不触发:确认 amis 版本 ≥ 2.5.3,且onEvent中的actionType拼写正确。

十、延伸阅读

  • 模板概念文档:两种模板引擎的完整语法与注意事项
  • 数据映射文档:${xxx}取值、命名空间、过滤器全量清单
  • 表达式文档:1.5.0+ 新表达式语法与内置函数
  • 事件动作文档:onEventactions的完整配置说明

【免费下载链接】amis前端低代码框架,通过 JSON 配置就能生成各种页面。项目地址: https://gitcode.com/GitHub_Trending/am/amis

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询