持续重绘视图 编辑页面


英文原文:http://emberjs.com/guides/cookbook/working_with_objects/continuous_redrawing_of_views

问题

有时视图需要每隔几秒或者几分钟重绘一次。例如更新相对时间(如同twitter.com那样)。

解决方案

应用中有一个时钟对象,该对象有一pulse属性定时递增。希望将视图与pulse绑定,并在其增加时得到刷新。

时钟对象可以创建用于绑定到应用生成的新视图的对象,比如评论列表。

讨论

Cookbook: 持续重绘视图

ClockService对象

这里ClockService只是用于作为一个例子,它可能来自于一个第三方库。并且通过初始化注入到应用中。

在初始化过程中,tick方法通过Ember.run.later每250毫秒被调用一次。当到时间时,会设置一个属性。由于tick方法观察了一个递增属性,并且每次属性增加时另外一个周期也同时被触发。

1
2
3
4
5
6
7
8
9
10
11
12
13
var ClockService = Ember.Object.extend({
  pulse: Ember.computed.oneWay('_seconds').readOnly(),
  tick: function () {
    var clock = this;
    Ember.run.later(function () {
      var seconds = clock.get('_seconds');
      if (typeof seconds === 'number') {
        clock.set('_seconds', seconds + (1/4));
      }
    }, 250);
  }.observes('_seconds').on('init'),
  _seconds: 0,
});

绑定至pulse属性

在本技巧中,应用在初始化时注入了一个ClockService的实例,并且将一个控制器的clock属性设置为该实例。

1
2
3
4
5
6
7
Ember.Application.initializer({
  name: 'clockServiceInitializer',
  initialize: function(container, application) {
    container.register('clock:service', ClockService);
    application.inject('controller:interval', 'clock', 'clock:service');
  }
});

该控制器可以基于注入的clock实例的pulse属性来设置任意属性。

本例中seconds属性绑定到控制器的clock对象的pulse属性。属性clock.pulse`在初始化时被注入。

控制器有(会话)数据来显示seconds给访问者,而且少数用于Handlebars模板的条件属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
App.IntervalController = Ember.ObjectController.extend({
  secondsBinding: 'clock.pulse',
  fullSecond: function () {
    return (this.get('seconds') % 1 === 0);
  }.property('seconds'),
  quarterSecond: function () {
    return (this.get('seconds') % 1 === 1/4);
  }.property('seconds'),
  halfSecond: function () {
    return (this.get('seconds') % 1 === 1/2);
  }.property('seconds'),
  threeQuarterSecond: function () {
    return (this.get('seconds') % 1 === 3/4);
  }.property('seconds')
});

一个评论列表的控制器,每条评论在被添加到列表时,会得到一个新的时钟实例。评论条目控制器设置seconds绑定,用于在模板中显示评论创建了多长时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
App.CommentItemController = Ember.ObjectController.extend({
  seconds: Ember.computed.oneWay('clock.pulse').readOnly()
})

App.CommentsController = Ember.ArrayController.extend({
  needs: ['interval'],
  itemController: 'commentItem',
  actions: {
    add: function () {
      this.addObject(Em.Object.create({
        comment: $('#comment').val(),
        clock: ClockService.create()
      }));
    }
  }
});

显示pulse的Handlebars模板

seconds的值是从pulse属性计算得来的。控制器有些属性是用来选择一个控件来渲染的,fullSecondquarterSecondhalfSecondthreeQuarterSecond

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{{#if fullSecond}}
  {{nyan-start}}
{{/if}}
{{#if quarterSecond}}
  {{nyan-middle}}
{{/if}}
{{#if halfSecond}}
  {{nyan-end}}
{{/if}}
{{#if threeQuarterSecond}}
  {{nyan-middle}}
{{/if}}
<h3>You&apos;ve nyaned for {{digital_clock seconds}} (h:m:s)</h3>
{{render 'comments'}}

评论列表的一个模板:

1
2
3
4
5
6
7
<input type="text" id="comment" />
<button {{action add}}>Add Comment</button>
<ul>
  {{#each}}
    <li>{{comment}} ({{digital_clock clock.pulse}})</li>
  {{/each}}
</ul>

格式化时钟显示(h:m:s)的Handlebars助手

本助手在模板中这样使用:{{digital_clock seconds}}seconds是控制器要显示的一个属性(h:m:s)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Ember.Handlebars.registerBoundHelper('digital_clock', function(seconds) {
  var h = Math.floor(seconds / 3600);
  var m = Math.floor((seconds % 3600) / 60);
  var s = Math.floor(seconds % 60);
  var addZero = function (number) {
    return (number < 10) ? '0' + number : '' + number;
  };
  var formatHMS = function(h, m, s) {
    if (h > 0) {
      return '%@:%@:%@'.fmt(h, addZero(m), addZero(s));
    }
    return '%@:%@'.fmt(m, addZero(s));
  };
  return new Ember.Handlebars.SafeString(formatHMS(h, m, s));
});

注意

为了深入探究这个概率,可以尝试添加一个时间戳,并通过与当前时间比较来更新时钟的pulse。在用户将计算机设置为睡眠后,再唤醒后重新打开浏览器时也应该更新pulse属性。

链接

源代码:

更多相关内容: