表达式
在 form 中的字段进行条件显示时,visibleOn 的值可以使用表达式。
表达式首先需要经过语法处理器编译
js
// \amis\packages\amis-formula\src\parser.ts
js
// amis/packages/amis-core/src/utils/formula.ts
/**
* formulaExec 运算器:根据当前字符串类型执行对应运算,也可按指定执行模式执行运算
*
* 运算模式(execMode)支持以下取值:
* 1. tpl: 按模板字符串执行(JavaScript 模板引擎),比如:Hello ${amisUser.email}、<h1>Hello</h1>, <span>${amisUser.email}</span>;
* 备注: 在模板中可以自由访问变量,详细请见:https://www.lodashjs.com/docs/lodash.template;
* 2. formula: 按新版公式表达式执行,用于执行 ${ xxx } 格式的表达式;
* 支持从window、localStorage、sessionStorage获取数据,比如:${num1 + 2}、${ls:env}、${window:document}、${window:document.URL}、${amisUser.email};
* 详细请见:https://aisuda.bce.baidu.com/amis/zh-CN/docs/concepts/data-mapping#namespace
* 3. evalFormula: 按新版公式表达式执行,用于执行 ${ xxx } 和 非${ xxx } 格式的表达式(evalMode 为 true,不用 ${} 包裹也可以执行),功能同 formula 运算模式;
* 4. js: 按Javascript执行,表达式中可以通过data.xxx来获取指定数据,并且支持简单运算;
* 比如:data.num1 + 2、this.num1 + 2、num1 + 2;(备注:三个表达式是等价的,这里的 this 就是 data。)
* 5. var: 以此字符串作为key值从当前数据域data中获取数值;性能最高(运行期间不会生成ast和表达式运算);
* 6. true 或者 false: 当execMode设置为true时,不用 ${} 包裹也可以执行表达式;
* 7. collect: 用于从表达式中获取所有变量;
*
* 备注1: 用户也可以使用 registerFormulaExec 注册一个自定义运算器;
* 备注2: 模板字符串 和 Javascript 模板引擎 不可以交叉使用;
* 备注3: amis 现有的 evalFormula 方法,可执行 ${} 格式类表达式,但不支持 filter 过滤器,所以这里用 resolveValueByName 实现;
* 备注4: 后续可考虑将 amis现有的运算器都放这里管理,充当统一的运算器入口。
*/
js: (expression: string, data?: object) => {
let debug = false;
const idx = expression.indexOf('debugger');
if (~idx) {
debug = true;
expression = expression.replace(/debugger;?/, '');
}
let fn;
if (expression in FORMULA_EVAL_CACHE) {
fn = FORMULA_EVAL_CACHE[expression];
} else {
fn = new Function(
'data',
'utils',
`with(data) {${debug ? 'debugger;' : ''}return (${expression});}`,
);
FORMULA_EVAL_CACHE[expression] = fn;
}
data = data || {};
let curResult = undefined;
try {
// this总是指向函数定义时指向的data对象,
curResult = fn.call(data, data, getFilters());
} catch (e) {
console.warn(
'[formula:js]表达式执行异常,当前表达式: ',
expression,
',当前上下文数据: ',
data,
);
return expression;
}
return curResult;
};
在 js 执行模式下,表达式可以直接访问 data 中的数据,也可以使用简单的运算。它会使用 new Function 来动态创建一个函数,将表达式嵌入函数体中执行。
从源代码中分析得知,可以在表达式中使用 debugger 开启调试,但是跟数学函数会有冲突。
在 amis 中,表达式使用的是 JavaScript 语法,支持使用变量和函数。 其中 this 跟 data 两个变量未跟预期一样是表示同样的对象。
表达式中 this 总是指向函数定义引用的变量域,比如是 form 对象。但是表达式中的 data 对象却是指向 data 同名变量。如果一个 form 在提交后,data 对象发生了变化,在接口中返回一个 data 对象,这时 data 变量会变覆盖!