MIP 表达式

在数据驱动机制当中提到了 MIP.setData()m-bindm-text 数据绑定都支持写一些表达式来完成一定程度的数据计算。比如:

1
2
3
4
5
6
<div on="tap:MIP.setData({ a: isActive ? (1 + 3) : 2, b: b + 1, c: [2, 1, 3].slice(1) })" ></div>

例子中的 isActive ? (1 + 3) : 2b + 1[2, 1, 3].slice(1) 都属于表达式。

这类表达式具有以下特点:

  1. 能读取并操作在 <mip-data> 中声明的变量;
  2. 支持有限的运算符;
  3. 支持有限的方法;

数据

可用于运算的数据包括以下几种:

  1. 定义在 <mip-data> 或者通过 MIP.setData() 所添加的数据,可直接根据对应数据的命名空间、属性名称,使用属性运算符(点运算符或计算属性)获取相应的数据。如 auserInfo.name 等等;
  2. 字面量数据,包括字符串、数字、null、undefined、字面量数组、字面量对象等等;
  3. 事件触发时所携带的数据,通过 event.xxx 进行获取,如 inputchange 事件,可通过 event.value 获取当前输入框的内容;

运算符

MIP 支持有限的运算符,利用这些运算符的相互组合,基本能够完成绝大多数的数据计算要求。

三元运算符

类型说明示例
expr ? expr : expr条件运算符a > b ? 'large' : 'small'

二元运算符

普通运算

类型说明示例
expr + expr加法1 + 1
'Hello ' + 'World'
expr - expr减法2 -1
expr * expr乘法1 * 2
expr / expr除法3 / 4
expr % expr取模4 % 2

逻辑运算

类型说明示例
expr && exprisActive && 'active'
expr || exprisActive || 'inactive'
expr > expr大于4 > 3
expr >= expr大于或等于8 >= 8
expr < expr小于a < b
expr <= expr小于或等于6 <= a
expr == expr相等null == undefined
expr === expr全等0 === 0
expr != expr不等a != null
expr !== expr不全等a !== '1'

一元运算符

类型说明示例
!expr!a
+expr转为数字+'1'
-expr负数-1

其他

类型说明示例
( expr )分组运算符(小括号)1 + (2 - 3)
{ attr: vaue }字面量对象{a: 1, b: 2, c: 3 + 4}
[ item, item ]字面量数组[2, 1, 3]
expr . attr属性运算符(点运算符)userInfo.name
expr[ expr ]计算属性userInfo['name']
expr( params )执行函数,只支持白名单方法调用encodeURIComponent('a=1&b=2')
[2, 1, 3].sort()

注意: 变量定义(var a = 0)、赋值(a = 10086)、new、if、for 等等这些都是不支持的。

白名单方法

白名单方法包括两类:全局方法和原型链方法。

全局方法

MIP 在数据驱动表达式当中支持的全局方法包括两类,一类是原生 window 下面的一些安全方法,比如 encoodeURICompoentpareInt 等等,一类是为了简化写法而将一部分方法进行改写,比如 Math.max(1, 2) 在 MIP 表达式中可直接使用 max(1, 2)。下面的表格列举了目前支持的全局方法说明:

函数名原挂载对象示例
encudeURI
encodeURIComponent
decodeURI
decodeURIComponent
isNaN
isFinite
parseFloat
parseInt
window// 返回 1.024
parseFloat('1.04')
keys
values
assign
Object// 返回 ['a', 'b', 'c']
keys({a: 1, b: 2, c: 3})
abs
ceil
floor
sqrt
log
max
min
random
round
sign
Math// 返回 2
abs(-2)

原型链方法

MIP 还支持使用部分原型链方法,比如下面举例的一些常见的字符串和数组操作:

1
2
3
4
5
// 结果是 '2,4' '213'.split(',') .map(num => num + 1) .slice(1) .join(',')

这里的 splitmapslicejoin 就分别是 String 和 Array 的原型链方法,MIP 会首先检测待操作的数据或对象是否存在该原型链方法,只有当存在了才会执行。下面的列表中列举了目前支持的原型链方法。

对象类型方法示例
Arrayconcat
filter
indexOf
join
lastIndexOf
map
reduce
slice
some
every
find
sort(修改)
splice(修改)
为了提升 MIP 表达式中的数组操作体验,我们修改了 sort 和 splice 方法,这两个方法将不会对原数组造成影响。
其中 sort 将返回排序后的新数组;
同时 splice 返回进行插入或删除操作之后的新数组。
// 返回新的对象 [1, 2, 3]
[2, 1, 3].sort()
// 返回新的对象 [1, 3]
[1, 2, 3].splice(1, 1)
// false
[1, 2, 3].some(num => num > 4)
NumbertoExponential
toFixed
toPrecision
toString
// 返回 1.2
(1.23).toFixed(1)
StringcharAt
charCodeAt
concat
indexOf
lastIndexOf
slice
split
substr
substring
toLowerCase
toUpperCase
// 返回 ['1', '2', '3']
'123'.split()

函数表达式

在上面介绍的原型链方法当中,不少方法都要求传入函数作为参数。在这里 MIP 表达式允许写单行箭头函数

这些箭头函数应该满足以下规则:

  • 仅允许写单行箭头函数,不支持 function,不支持 return
1
2
3
4
5
6
7
// 正确 [1, 2, 3].map(item => item + 1) // 错误,不支持 return [1, 2, 3].map(item => { return item + 1 }) // 错误,不支持 function 也不支持 return [1, 2, 3].map(function (item) { return item + 1 })
  • 当函数参数仅有一个时,禁止写圆括号:
1
2
3
4
5
6
7
// 正确,单参数应去除圆括号 [1, 2, 3].map(item => item + 1) // 正确,多参数请添加圆括号 [1, 2, 3].reduce((result, item) => result + item, 0) // 错误,单参数应去除圆括号 [1, 2, 3].map((item) => item + 1)
  • 不允许直接将全局方法作为参数直接传入:
1
2
3
4
5
// 正确,声明匿名箭头函数作为参数传入 ['1.2', '3.4', '5.6'].map(item => parseFloat(item)) // 错误,直接将全局方法作为参数传入,表达式解析会报错 ['1,2', '3.4', '5.6'].map(parseFloat)
  • 箭头函数主体应同样满足 MIP 表达式的规范和要求
1
2
3
4
5
// 正确,箭头函数主体满足 MIP 表达式的规范要求 [1, 2, 3].map(item => item + 1) // 错误,MIP 表达式不支持 ++ 运算符 [1, 2, 3].map(item => item++)