计算字段与过滤器

Regular 提供了两种自定义表达式读写的方式 —— 计算字段过滤器

1. 计算字段

计算字段在 options 通过 computed 字段注册,可以避免书写冗余的表达式

1.1. 计算字段的定义

使用计算字段相当于手动构造 表达式对象

对象包含getset(可选)方法

  • 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是可选的


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
  • last

    • get: list[list.length-1]

results matching ""

    No results matching ""