0

假设我正在 Ember 中创建一个可重用的组件,并且我想要一个辅助函数来调用其中定义的另一个辅助函数。例如,

App.SomeCoolComponent = Ember.Component.extend

  offset: 50

  position: (x) -> x * 100

  offsetPosition: # would like (x) -> position(x) + offset

因此,从概念上讲,返回一个函数,该函数将评估 x 处的位置、添加偏移量并返回值。显然这是一个愚蠢的例子,我可以offSetPosition不调用就直接编写position,但是在重复代码的更复杂的场景中。问题是我不知道如何让它工作。我试过

  offsetPosition: (x) -> @get('position')(x) + @get('offset')

失败是因为@get没有在函数中定义,它有错误的范围。我试图Ember.computed在不同的地方插入类似的东西也没有运气,例如以下也不起作用:

  offsetPosition: Ember.computed(->
    (x) -> @get('position')(x) + @get('offset')).property('position', 'offset')

这样做的正确方法是什么?

Ember 版本 1.3.0-beta.1+canary.48513b24。提前致谢!

编辑:似乎我的问题源于将函数传递给 d3 调用。例如:

App.SomeCoolComponent = Ember.Component.extend

  offset: 50

  position: (d, i) -> i * 100

  offsetPosition: (d, i) ->
    @position(d, i) + @get('offset')

  # Some other code not shown

  didInsertElement: ->
    data = [1, 2, 3]
    i = 1
    d = data[i]
    console.log(@position(d, i)) # works
    console.log(@offsetPosition(d, i)) # works

    d3.select('svg').selectAll('circle').data(data).enter().append('circle')
      .attr('cx', @position) # works
      .attr('cy', @offsetPosition) # fails
      .attr('r', 30)

错误信息是Uncaught TypeError: Object #<SVGCircleElement> has no method 'position'

关于如何解决这个问题的任何想法?

4

2 回答 2

1

方法(又名非计算属性)在当前上下文中,应该像方法一样调用,而不是使用 getter/setter。

offsetPosition: (x) -> @position(x) + @get("offset")

位置:(x) -> x * 100

这是一个例子:http ://emberjs.jsbin.com/eWIYICu/3/edit

App.AnAppleComponent = Ember.Component.extend({
  offset: 50,

  position: function(x) {
    return x * 100;
  },

  offsetPosition: function(x) {
    return this.position(x) + this.get('offset');
  },

  displayOffset: function(){
    return this.offsetPosition(Math.floor(Math.random() * 10) + 1);
  }.property('offset')

});

我个人会创建一个 mixin 并在其中添加我的方法,然后在需要该逻辑的地方添加 mixin。Mixin 在它们被添加到的任何东西的范围内。

顺便说一句,您可以在应用程序的任何位置使用 Ember.Get(object, 'propertyOnObject')。

作为对您的编辑的响应,您将方法传递给那些属性值而不是那些方法的值(这就是它在上面工作但不在下面工作的原因)。很有可能,因为您正在发送这些方法 jquery 稍后会在超出范围的情况下应用这些方法。

didInsertElement: ->
  data = [1, 2, 3]
  i = 1
  d = data[i]
  position = @position(d, i)
  offsetPosition = @offsetPosition(d, i)
  console.log position
  console.log offsetPosition
  d3.select("svg").selectAll("circle").data(data).enter().append("circle").attr("cx", position).attr("cy", offsetPosition).attr "r", 30

我有一种感觉,你希望它能够动态更新或类似的东西,如果你真的想要使用计算属性,Ember 的培根。这是苹果组件的更新版本:

http://emberjs.jsbin.com/eWIYICu/5/edit

<div {{bind-attr style='dynamicStyle'}}>

dynamicStyle: function(){
  var rgb = this.get('rgb'),
      rgb1 = rgb * 21 % 255,
      rgb2 = rgb * 32 % 255,
      rgb3 = rgb * 41 % 255;
  return 'background-color:rgb(' + rgb1 + ',' + rgb2 + ',' + rgb3 + ');';
}.property('rgb'),
于 2013-10-27T06:53:33.010 回答
1

问题是您正在将一个函数offsetPosition(它引用this并期望它指向App.SomeCoolComponent)传递给 D3 回调,其中this替换为DOMElement.

您可以通过两种方式解决问题:

  1. 使用fat arrow syntax

    d3.select('svg').selectAll('circle').data(data).enter().append('circle')
      .attr('cx', @position) # works
      .attr('cy', (d, i) => @offsetPosition(d, i))
      .attr('r', 30)
    
  2. 显式使用bind

    d3.select('svg').selectAll('circle').data(data).enter().append('circle')
      .attr('cx', @position) # works
      .attr('cy', @offsetPosition.bind(this))
      .attr('r', 30)
    
于 2013-10-27T16:05:28.357 回答