计算字段与过滤器
Regular 提供了两种自定义表达式读写的方式 —— 计算字段 和 过滤器
1. 计算字段
计算字段在 options 通过 computed
字段注册,可以避免书写冗余的表达式
1.1. 计算字段的定义
使用计算字段相当于手动构造 表达式对象
对象包含get
和set
(可选)方法,
get(data)
: 属性的 getter 函数,定义 读 逻辑- data:
data
指向 component.data - this:
this
指向组件 component
- data:
set(value, data)
: 属性的 setter 函数,定义 写 逻辑- value: the value to set
- data:
data
指向 component.data - this:
this
指向组件 component
其中set是可选的
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函数存在
const Component = Regular.extend({
computed: {
fullname: function(data){
return data.first + "-" + data.last;
}
}
})
上例你也可以简写成一个表达式
const Component = Regular.extend({
computed: {
fullname: `first+ '-' + last`
}
})
完整的使用范例
const Component = Regular.extend({
template: `
<div>fullname: <input r-model={fullname}></div>
<div>first: <input r-model={first}></div>
<div>last: <input r-model={last}></div>
<div>{welcome}</div>
`,
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,是可读可写的计算字段,可用于双向绑定
1.2. 计算字段的读写
如果你需要在 javascript 对定义的计算进行读写会失败,因为要兼容低版本IE,计算字段并非通过Object.defineProperty
实现,不过 Regular 提供了途径来获取计算字段 -- $get
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
也可以应用与所有表达式。
component.$get('"Hello, " + fullname')
参考
1.3. 计算字段范例: 「全选/反选」
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
<ul>
{#list list as item}
<li>
<label><input type="checkbox" r-model={item.selected}><b>{item.text}</b></label>
</li>
{/list}
</ul>
<label><input type="checkbox" r-model={selectAll}><b>Select All</b></label>
2. 过滤器 - filter
过滤器是 Regular 中的一种扩展表达式类型 , 你可以和+
、-
符号一样去使用它。
Syntax
Expression| fitlerName: arg1, arg2,... argN
Example
<div>{list| join: '+'}</div>
2.1. 定义过滤器
你可以通过Regular.filter
来定义一个过滤器。
下例会定义一个join数组为字符串的,它接受一个split参数
Regular.filter({
'join': function( list, split ){
return list.join(split||'-')
}
})
new Regular({
template:`
<div>{list|join:'+'}</div>
`,
data: {
list: ['Add', 'Update', 'Delete']
}
})
2.2. 过滤器参数
过滤器参数可以传入任意个,他们会依次传入到过滤器定义的get和 set 函数中,过滤器参数可以是任意表达式
Reuglar.extend({
template:`
<div>{list|join:'+'}</div>
`
})
2.3. 过滤器的优先级
过滤器是一个优先级小于三元表达式(如 a?b:c
)的表达式,与标准表达式一样,你可以使用()
来提升它的优先级
<div>{ 'add: ' + ([1,2,3]|join: '+') } = 6</div>
输出
<div> add: 1+2+3 = 6</div>
2.4. 日期格式化过滤器: format
以下实现了一个简化的 Regular 日期过滤器
Example
创建一个简单的日期格式化过滤器
// 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) : "";
});
})
然后
<p>{time| format: 'yyyy-MM'}</p>
2.5. 双向过滤器
Regular 支持一个简单的概念: 双向过滤器,使得过滤器可以代理写操作,与计算字段类似,你需要理解一个表达式对象实际是由 get(读操作) 和 set (写操作) 构成
双向过滤器如其名,经常会用在双向绑定上,由于这个特性,r-model
可以变相与一个数组类型实现双向绑定。
以 {[1,2,3]|join: '-'}
为例
过滤器定义
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
读函数
{JSON.stringify(array)}
<input r-model={array|join:'-'} >
说明
过滤器劫持了读写,使得字符串类型和数组变相实现了双向绑定。
- 写过程: 从表单元素的
input.value
到数据array
,先经过 set 函数,从 字符串 > 数组 - 读过程: 从数据
array
到表单元素的input.value
,先经过 get 函数,从 数组 > 字符串
如表达式章节所述, 部分全局变量如
JSON
在模板中可用
2.6. 过滤器与计算字段的对比
- 过滤器是一个可复用的抽象,而计算字段是一个写死的字段定义
- 计算字段使用更简洁
2.7. 内置过滤器
为了控制框架体积,Regular 只有少量内置过滤器,其中 不包含format! ,你参考上例实现,或直接使用更详细的包,例如 moment.js
json
: 这是一个双向过滤器- get:
JSON.parse
- set:
JSON.stringify
- get:
last
- get:
list[list.length-1]
- get: