编写在 d3 ember 组件中调用其他方法的方法



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

App.SomeCoolComponent = Ember.Component.extend
  offset: 50
  position: (x) -> x * 100
  offsetPosition: # would like (x) -> position(x) + offset
因此,从

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

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

失败是因为@get函数中未定义,它的作用域错误。 我曾尝试在各个地方插入诸如Ember.computed之类的东西,但没有运气,例如以下内容也不起作用:

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

正确的方法是什么?

余烬版本 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'

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

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

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

  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)
    

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

偏移位置: (x) -> @position(x) + @get("偏移")

位置: (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。 混合在它们被添加到的任何范围内。

顺便说一句,您可以在应用程序的任何地方使用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'),

最新更新