Evaluate Placeholders 求值占位符
Evaluate Placeholders 求值占位符可同时用于 transform 及参数注入。与普通的 Placeholders 占位符不同,求值占位符可以编写真正的 JavaScript 代码(实际是 JavaScript 的表达式子集),因此它的能力更丰富、使用更灵活。
示例
your-prop-a: "<% _.find(EVENT.detail, item => item.id === QUERY.objectId) %>"
your-prop-b: "<% PIPES.yamlStringify(DATA.cellData) ?? '' %>"
your-prop-c: "<% `/your-app/${QUERY.path}?quality=${QUERY.q}` %>"
transform:
your-prop-d: "<% DATA.cellData + QUERY.id %>"
说明
求值占位符是「以 <% + 至少一个空白符开始,并且以至少一个空白符 + %> 结束的字符串」,它的内部包裹一个且仅一个 JavaScript 表达式。
例如:
properties:
# ✅ Will Work
a: "<% `/your-app/${QUERY.path}?quality=${QUERY.q}` %>"
# 🚫 Not starting with `<% `
b: "/bad/<% QUERY.path %>"
# 🚫 Not ending with ` %>`
c: "<% QUERY.path %>/bad"
# 🚫 Missing spaces
d: "<%QUERY.path%>"
求值占位符中可以使用大部分 JavaScript 语法,出于避免意外的错误使用、安全、框架复杂度等方面考虑,支持的语法子集将限制在 Expression 中,并剔除了赋值相关的语法或操作,具体的支持清单见本文档最后的附录。
新的占位符可同时用于 transform 及参数注入。下面列举一些常见的将原占位符改写为求值占位符的示例。
old: "${QUERY.id}"
new: "<% QUERY.id %>"
# Path parameters and query
old: "/your-app/${objectId}?quality=${QUERY.q}"
# Template literal
new: "<% `/your-app/${PATH.objectId}?quality=${QUERY.q}` %>"
# Pipes
old: "${EVENT.detail | yamlStringify }"
new: "<% PIPES.yamlStringify(EVENT.detail) %>"
# Transform
old: "@{cellData}"
new: "<% DATA.cellData %>"
# Events
old: "${EVENT.detail}"
new: "<% EVENT.detail %>"
# Mix transform and query
old: "@{cellData.id}/detail/${QUERY.id}"
new: "<% `${DATA.cellData.id}/detail/${QUERY.id}` %>"
内置对象
求值占位符支持所有原参数注入支持的对象:
| 对象 | 说明 |
|---|---|
QUERY | URL query 参数。使用 ${QUERY} 将得到原始 URLSearchParams 对象,配合管道 string 可以得到拼接好的 query 参数,如 a=1&b=2。 |
QUERY_ARRAY | URL query 参数,在解析某项参数值时将返回数组。例如当 URL 为 ?a=1&a=2 时,${QUERY_ARRAY.a} 将转换为 ["1", "2"] |
HASH | URL hash 参数,如 #your-anchor |
ANCHOR | URL hash 参数去掉前缀 #,如 your-anchor |
APP | 微应用的配置(对应 storyboard 的 app 字段),例如 ${APP.homepage} |
EVENT | 事件对象,仅适用于事件配置中 |
SYS | 系统信息,当前包含当前登录用户名: username, 当前登录用户实例 ID: userInstanceId |
FLAGS | 特性开关信息,key 为开关名,value 为是否启用的 boolean 值 |
CTX | Context 上下文对象。 |
并且还额外支持了一些对象:
| 对象 | 说明 |
|---|---|
DATA | Transform 使用的原始数据。 |
PATH | URL path 参数。例如对于 path /object/:objectId 可以使用 <% PATH.objectId %> 引用。 |
PIPES | 管道字典。例如可以使用 <% PIPES.yamlStringify(whatever) %> 来引用 yamlStringify 管道函数。 |
PARAMS | URLSearchParams 原始对象。 |
SEGUE | Segues 页面切换,使用 SEGUE.getUrl(...) 获取 URL。 |
ALIAS | Route Alias 路由别名,使用 ALIAS.getUrl(...) 获取 URL。 |
I18N | 使用 I18N(...) 显示应用预设的国际化内容。 |
I18N_TEXT | 使用 I18N_TEXT(...) 根据当前语言设置转换带有国际化设置的字典为对应文本内容。 |
IMG | 使用 IMG.get(...) 获取图像资源的 URL。 |
PROCESSORS | Custom Processors 自定义加工函数。 |
TPL | 自定义模板的属性变量。 |
PERMISSIONS | 使用 PERMISSIONS.check("your:action-x") 检查当前登录用户是否拥有指定权限。可以传递多个 actions,当用户拥有所有指定权限时返回 true,否则返回 false。 |
_ | Lodash 函数库(除标明了 mutates 原始数据的函数、Function 一节的函数外)。例如 <% _.flatten(whatever) %>。 |
moment | Moment 函数库(除了可能做 mutate 操作的函数外,如 updateLocale() 等)。例如 <% moment().format(...) %>。 |
LOCAL_STORAGE | localStorage 存储的信息,支持 getItem 方法获取 localStorage 项,例如 <% LOCAL_STORAGE.getItem("your-key") %>。需要写入数据(localStorage.setItem(...))或者移除项(localStorage.removeItem(...)),请使用内建处理器:localStorage.*。 |
SESSION_STORAGE | sessionStorage 存储的信息,支持 getItem 方法获取 sessionStorage 项,例如 <% SESSION_STORAGE.getItem("your-key") %>。需要写入数据(sessionStorage.setItem(...))或者移除项(sessionStorage.removeItem(...)),请使用内建处理器:sessionStorage.*。 |
INSTALLED_APPS | 使用 <% INSTALLED_APPS.has("your-app-id") %> 来判断指定微应用是否已安装。也可以使用 <% INSTALLED_APPS.has("your-app-id", ">=1.2.3") %> 来判断指定微应用已安装并且版本满足指定规则(目前仅支持 >= > = < <= 这几种比较符,注:属于 semver 子集) |
TAG_URL | 使用 JavaScript 的 Tagged Template 来实现对 URL 参数的自动编码(会忽略 / 的编码)。例如 <% TAG_URL`${APP.homepage}/list?q=${q}` %> 可以得到 /hello/world/list?q=a%26b (假设 APP.homepage 为 /hello/world、q 为 a&b)。 |
SAFE_TAG_URL | 类似于 TAG_URL 但会执行严格编码(会转换 / 为 %2F)。 |
FN | 调用 Storyboard Functions |
BASE_URL | 页面的根目录,现阶段通常为 "/next",未来可能为 "",示例配置:{action: "window.open", args: [`${BASE_URL}${APP.homepage}/x/y/z`]。 |
PATH_NAME | URL 路径名,例如当 URL 为 http://www.uwintech.cn/next/path/name?a=a 时,<% PATH_NAME %> 将转换为 /path/name 。 |
MEDIA | 媒体查询全局对象。 |
高级
由于表达式(包括占位符和 Transform)计算得到的数据通常包含来自用户输入的数据,因此为了避免意外解析(例如某数据需要保存原始内容的表达式字符串),表达式得到的数据的内部的其它表达式在消费时不会执行解析。同时也避免了类比于 XSS 的攻击,例如攻击者将某实例描述字段设置为包含恶意表达式的内容。
递归标记
通过添加递归标记 ~ 例如 <%~ DATA %>,可以允许该表达式得到的数据的内部的其它表达式(包括占位符和 Transform)在消费时继续执行解析。该标记适用于 Dashboard 等场景:数据库中的数据明确包含需要被解析的表达式。
附录
支持的 JavaScript 语法清单:
- ✅ ArrayExpression:
[1, 2, 3] - ✅ ObjectExpression:
{ a: 1 } - ✅ ArrowFunctionExpression:
() => 1 - ✅ UnaryExpression <Partial>
- ✅
-+!typeofvoid
- ✅
- ✅ BinaryExpression <Partial>
- ✅
==!====!== - ✅
<<=>>= - ✅
+-*/%** - ✅
|>(pipeline operators! minimal version)
- ✅
- ✅ LogicalExpression:
||&&??(nullish coalescing 💅) - ✅ MemberExpression:
a.b - ✅ OptionalMemberExpression:
a?.b(optional chaining 💅) - ✅ ConditionalExpression:
a ? 1 : 2 - ✅ CallExpression:
a(1) - ✅ SequenceExpression:
a, b - ✅ TemplateLiteral:
`/your/${path}`- ✅ Tagged template:
TAG_URL`${APP.homepage}/list?q=${q}`
- ✅ Tagged template:
- ✅ SpreadElement:
[1, ...a]{ a, ...rest } - ✅ ObjectPattern:
({ a, b }) => null - ✅ ArrayPattern:
([ a, b ]) => null - ✅ RestElement:
(...args) => null - ✅ AssignmentPattern:
(a = 1) => null - ✅ NewExpression <Partial>
- ✅
new Array(...) - ✅
new Date(...) - ✅
new Map(...) - ✅
new Set(...) - ✅
new WeakMap(...) - ✅
new WeakSet(...) - ✅
new URLSearchParams(...)
- ✅
不支持的 JavaScript 语法清单:
- 🚫 Statements:
if (a) {} - 🚫 Declarations:
var a - 🚫 FunctionExpression:
function a() {} - 🚫 UpdateExpression:
++i - 🚫 AssignmentExpression:
a = 1 - 🚫 Class:
class A {} - UnaryExpression <Partial>
- 🚫
~delete
- 🚫
- BinaryExpression <Partial>
- 🚫
<<>>>>> - 🚫
|^&ininstanceof
- 🚫
- 🚫 Raw strings in tagged templates
浏览器原生 DOM 对象(值)支持清单:
- Object <Partial>
- ✅
entries()fromEntries()keys()values() - 🚫 Other Methods
assign(), etc.
- ✅
- ✅ Array
- ✅ Boolean
- ✅ Date
- ✅ Infinity
- ✅ JSON
- ✅ Math
- ✅ NaN
- ✅ Number
- ✅ String
- ✅ atob
- ✅ btoa
- ✅ decodeURI
- ✅ decodeURIComponent
- ✅ encodeURI
- ✅ encodeURIComponent
- ✅ isFinite
- ✅ isNaN
- ✅ parseFloat
- ✅ parseInt
- location <Partial>
- ✅ href (readonly)
- ✅ origin (readonly)
- ✅ host (readonly)
- ✅ hostname (readonly)
变更历史
| 组件 | 版本 | 变更 |
|---|---|---|
| brick_next | 2.65.31 | 支持 MEDIA |
| - | 2.63.29 | 支持 PATH_NAME |
| - | 2.40.1 | 支持 BASE_URL |
| - | 2.34.3 | 支持 INSTALLED_APPS.has(appId, matchVersion?) |
| - | 2.31.7 | 支持 FN 和指数运算 ** |
| - | 2.29.15 | 支持 atob 和 btoa |
| - | 2.27.3 | 支持 TAG_URL 和 SAFE_TAG_URL |
| - | 2.27.3 | 支持 TAG_URL 和 SAFE_TAG_URL |
| - | 2.19.14 | 支持 INSTALLED_APPS.has(...) |
| - | 2.19.8 | 支持 new URLSearchParams(...) |
| - | 2.15.23 | 支持 LOCAL_STORAGE.getItem("your-key") |
| - | 2.10.0 | 支持 PERMISSIONS.check(...) |
| - | 2.5.2 | 支持部分 NewExpression,例如 new Set(...) |
| - | 1.26.3 | 支持 pipeline operators minimal version |
| - | 1.21.10 | 支持:ALIAS.getUrl(...) |
| - | 1.16.17 | 支持:SEGUE.getUrl(...) |
| - | 1.16.10 | 开始支持求值占位符 |