0

我正在尝试编写具有三种状态的 Ember 视图。具体来说,提交按钮从“提交”转换为“保存...”再到“完成!” 有很多方法可以实现这一目标,但我想知道从 Ember 的角度来看,在不编写糟糕代码的情况下实现这一目标的“最佳实践”是什么。

目前我有以下代码:

UiControls.SubmitButton = Ember.View.extend({

  template: function() {  
    var template = '{{#if view.isNotStarted}}Submit{{/if}}';
    template += '{{#if view.isStarted}} <i class="icon-spinner icon-spin"></i>Saving...{{/if}}';
    template += '{{#if view.isFinished}} <i class="icon-check-sign"></i>Finished!{{/if}}'
    return Ember.Handlebars.compile(template);
  }.property(),

  isNotStarted: true,
  isStarted: null,
  isFinished: null,

  classNames: ['btn', 'btn-green'],

  isDisabled: false,

  click: function(){
    if (!this.get('disabled')){
      this.set('isNotStarted', false);
      this.set('isStarted', true);
      this.set('isFinished', false);
      this.timer();
    }
  },

  /* Simulates a server call */
  timer: function(){
    (function(self){
      setTimeout(function(){
        self.set('isStarted', false);
        self.set('isFinished', true);
      }, 500);
    })(this);
  }
});

对我来说,这真的很难看——我们根据事件设置单独的布尔值,以便使用车把有目的地限制的条件语法。

想要的是一个车把结构,它接受类似于 Ember StateManager 属性的东西(不能使用 Handlebars 语法)。或者,至少,我想根据来自 StateManager 的计算属性更改我的模板(同样,不可能)。所以我的问题是,有没有更好的方法来编写上述代码,以防止通过大量的小布尔标志操作手动处理代码重复处理状态转换?

4

1 回答 1

2

对我来说,这真的很难看——我们根据事件设置单独的布尔值,以便使用车把有目的地限制的条件语法。

完全同意,这表明需要进行一些重构。

我想要的是一个车把结构,它接受类似于 Ember StateManager 属性的东西(不能使用 Handlebars 语法)。

如果您编写自定义车把助手,这是可能的,但老实说,我不推荐这种方法。

或者,至少,我想根据来自 StateManager 的计算属性更改我的模板(同样,不可能)

为什么不?猜测您的意思是即使您拥有该属性,也无法在没有所有布尔值的情况下更改模板。

所以我的问题是,有没有更好的方法来编写上述代码,以防止通过大量的小布尔标志操作手动处理代码重复处理状态转换?

是的。把手有这个限制的原因是为了防止复杂性和逻辑成为模板的一部分。例如,任何时候您需要根据某个值显示 3 个版本中的 1 个。这种逻辑属于视图或控制器层。

所以看你的例子,模板有两个方面需要改变

  • text:应该是“提交”、“正在保存...”或“完成!”
  • iconClassNames:空的,“icon-spinner icon-spin”或“icon-check-sign”

考虑到这一点,我们可以将模板简化为:

<i {{bindAttr class="view.iconClassNames"></i>{{view.text}}

并将属性添加到视图

UiControls.SubmitButton = Ember.View.extend({
  template: Ember.Handlebars.compile('<i {{bindAttr class="view.iconClassNames"></i>{{view.text}}'),
  classNames: ['btn', 'btn-green'],
  isDisabled: false,
  text: "Submitted",
  iconClassNames: "",
  click: function(){
    if (!this.get('disabled')){
      this.set('text', 'Saving...');
      this.set('iconClassNames', 'icon-spinner icon-spin');
      this.timer();
    }
  },

  /* Simulates a server call */
  timer: function(){
    (function(self){
      setTimeout(function(){
      this.set('text', 'Finished!');
      this.set('iconClassNames', 'icon-check-sign');
      }, 500);
    })(this);
  }
});

这适用于模拟,但并不理想。您确实希望 text 和 iconClassNames 成为boundstateManager。这意味着更改texticonClassNames要计算的属性。理想情况下,它们将根据模型对象的底层状态进行计算,并click()在控制器上定义,但对于模拟,它会是这样的:

UiControls.SubmitButton = Ember.View.extend({
  template: Ember.Handlebars.compile('<i {{bindAttr class="view.iconClassNames"></i>{{view.text}}'),
  classNames: ['btn', 'btn-green'],
  isDisabled: false,
  state: 'new',
  text: function() {
    //return appropriate button text based on state
  }.property('state'),
  iconClassNames: function() {
    //calculate text based on state
  }.property('state'),

  /* Simulates a server call */
  click: function(){
    if (!this.get('disabled')){
      this.set('state', 'saving');
      this.timer();
    }
  },

  /* Simulates a server call */
  timer: function(){
    (function(self){
      setTimeout(function(){
        self.set('state', 'finished');
      }, 500);
    })(this);
  }
});
于 2013-06-11T21:21:27.723 回答