# 计算字段与过滤器 Regular 提供了两种自定义[表达式](../reference/expression.md#setable)读写的方式 —— __计算字段__ 和 __过滤器__ ## 计算字段 {#computed} 计算字段在 [options](../reference/api.md#options) 通过 `computed` 字段注册,可以避免书写冗余的[表达式](../reference/expression.md) ### 计算字段的定义 使用计算字段相当于手动构造 __[表达式对象](../reference/expression.md#setable)__ __对象包含`get`和`set`(可选)方法__, - `get(data)`: 属性的 getter 函数,定义 __读__ 逻辑 - data: `data` 指向 component.data - this: `this` 指向组件 component - `set(value, data)`: 属性的 setter 函数,定义 __写__ 逻辑 - value: the value to set - data: `data` 指向 component.data - this: `this` 指向组件 component _其中set是可选的_ ```js const Component = Regular.extend({ computed: { fullname: { get: function(data){ return data.first + "-" + data.last; }, set: function(value, data){ var tmp = value.split("-"); data.first = tmp[0]; data.last = tmp[1]; } } } }) ``` __直接传入函数,它会作为getter函数存在__ ```javascript const Component = Regular.extend({ computed: { fullname: function(data){ return data.first + "-" + data.last; } } }) ``` 上例你也可以简写成一个表达式 ```javascript const Component = Regular.extend({ computed: { fullname: `first+ '-' + last` } }) ``` 完整的使用范例 ```javascript const Component = Regular.extend({ template: `
fullname:
first:
last:
{welcome}
`, computed: { welcome: `'Hello, '+ fullname`, fullname: { get: function(data) { return data.first + "-" + data.last; }, set: function(value, data) { const tmp = value.split("-"); data.first = tmp[0]; data.last = tmp[1]||''; } } } }) const component = new Component({ data: { first: '1', last: '2' } }).$inject(document.body); ``` __说明__ - `welcome`: 只读的计算字段 - `fullname`: 由于设置了set,是可读可写的计算字段,可用于双向绑定 ### 计算字段的读写 如果你需要在 javascript 对定义的计算进行读写会失败,因为要兼容低版本IE,计算字段并非通过`Object.defineProperty`实现,不过 Regular 提供了途径来获取计算字段 -- [$get](../reference/api.md#get) ```js const Component = Regular.extend({ computed:{ fullname: `first + '-' + last` } }) const component = new Component({ data: { first: 'Zheng' last: 'Haibo' } }); console.log(component.data.fullname) // undefined console.log(component.$get('fullname')) // 'Zheng-Haibo' ``` 实际上 `$get` 也可以应用与所有表达式。 ```js component.$get('"Hello, " + fullname') ``` __参考__ - [$get](../reference/api.md#) ### 计算字段范例: 「全选/反选」 ```java const ListComponent = Regular.extend({ computed: { selectAll: { // only every item is selected, we return true get: function( data ){ if(!data.list) return false; return data.list.filter( function(item){ return !!item.selected} ).length === data.list.length; }, set: function( value, data ){ if(!data.list) return // set every item.selected with passed value data.list.forEach(function(item){ item.selected = value; }) } } } }) ``` __template__ ```html ``` ## 过滤器 - filter 过滤器是 Regular 中的一种[扩展表达式类型](../reference/expression.md#filter) , 你可以和`+`、`-`符号一样去使用它。 __Syntax__ `Expression| fitlerName: arg1, arg2,... argN ` __Example__ ```html
{list| join: '+'}
``` ### 定义过滤器 你可以通过[`Regular.filter`](../reference/api.md#filter)来定义一个过滤器。 下例会定义一个join数组为字符串的,它接受一个split参数 ```javascript Regular.filter({ 'join': function( list, split ){ return list.join(split||'-') } }) new Regular({ template:`
{list|join:'+'}
`, data: { list: ['Add', 'Update', 'Delete'] } }) ``` ### 过滤器参数 过滤器参数可以传入任意个,他们会依次传入到过滤器定义的get和 [set](#two-way) 函数中,过滤器参数可以是任意表达式 ```js Reuglar.extend({ template:`
{list|join:'+'}
` }) ``` ### 过滤器的优先级 过滤器是一个优先级小于三元表达式(如 `a?b:c` )的表达式,与标准表达式一样,你可以使用`()`来提升它的优先级 ```html
{ 'add: ' + ([1,2,3]|join: '+') } = 6
``` __输出__ ```html
add: 1+2+3 = 6
``` ### 日期格式化过滤器: format 以下实现了一个简化的 Regular 日期过滤器 __Example__ 创建一个简单的日期格式化过滤器 ```javascript // simplest date format function fix(str) { str = "" + (str || ""); return str.length <= 1 ? "0" + str : str; } const maps = { 'yyyy': function(date) { return date.getFullYear() }, 'MM': function(date) { return fix(date.getMonth() + 1); }, 'dd': function(date) { return fix(date.getDate()) }, 'HH': function(date) { return fix(date.getHours()) }, 'mm': function(date) { return fix(date.getMinutes()) } } const trunk = new RegExp(Object.keys(maps).join('|'), 'g'); Regular.filter("format", function(value, format) { format = format || "yyyy-MM-dd HH:mm"; value = new Date(value); return format.replace(trunk, function(capture) { return maps[capture] ? maps[capture](value) : ""; }); }) ``` 然后 ```html

{time| format: 'yyyy-MM'}

``` ### 双向过滤器 {#two-way} Regular 支持一个简单的概念: 双向过滤器,使得过滤器可以代理写操作,与[计算字段类似](#computed),你需要理解一个[表达式对象](../reference/expression.md#setable)实际是由 __get__(读操作) 和 __set__ (写操作) 构成 双向过滤器如其名,经常会用在双向绑定上,由于这个特性,`r-model`可以变相与一个数组类型实现双向绑定。 以 `{[1,2,3]|join: '-'}` 为例 过滤器定义 ```js Regular.filter('join', { //["1","2","3"] - > '1-2-3' get: function(origin, split ){ return origin.join( split || "-" ); }, // **Important ** // '1-2-3' - > ["1","2","3"] set: function(dest, split ){ return dest.split( split || "-" ); } }) ``` > 说明: 过滤器定义传入函数,则自动成为 `get` 读函数 ```html {JSON.stringify(array)} ``` __说明__ 过滤器劫持了读写,使得字符串类型和数组变相实现了双向绑定。 - __写过程__: 从表单元素的`input.value` 到数据 `array`,先经过 __set__ 函数,从 __字符串 > 数组__ - __读过程__: 从数据`array`到表单元素的`input.value` ,先经过 __get__ 函数,从 __数组 > 字符串__ > 如[表达式章节](../reference/expression.md)所述, 部分全局变量如`JSON`在模板中可用 ### 过滤器与计算字段的对比 - 过滤器是一个可复用的抽象,而计算字段是一个写死的字段定义 - 计算字段使用更简洁 ### 内置过滤器 为了控制框架体积,Regular 只有少量内置过滤器,其中 __不包含format!__ ,你参考上例实现,或直接使用更详细的包,例如 [moment.js](https://momentjs.com/) - `json`: _这是一个双向过滤器_ - get: `JSON.parse` - set: `JSON.stringify` - `last` - get: `list[list.length-1]`