2

我开始使用Ractive,我想更好地了解如何制作可重用的组件。编写可在不同情况下使用的通用小部件非常容易。我的问题是,我的应用程序中的数据通常不是小部件所期望的形状,我不知道如何扩展小部件以使其更加特定于应用程序。

举一个具体的例子,假设我正在编写一个 Ractive 组件来设计折线图。我会做一些类似的事情

var Chart = Ractive.extend({
  template: chart,
  data: {
    points_to_path: function(points) {
      // whatever
    }
  }
});

使用类似的模板

<svg>
  {{# points_to_path(points) }}
    <path d="{{ path }}" />
  {{/ end of path }}
</svg>

这个组件可以像这样使用

var chart = new Chart({
  data: {
    points: [[1, 2], [3, 4], [5, 6]]
  }
});

现在假设我实际上需要使用这样的组件。points可能我的数据不是像上面那样以双分量数组的形式出现。也许我有更多类似的东西

[
  {
    date: 'aug 2011',
    value: 12.51
  },
  {
    date: 'sep 2011',
    value: 12.38
  },
  ...
]

所以,我想做的是制作一个更具体的应用程序Chart,以接受上述形式的数据。我没有看到一个简单的方法来做到这一点Chart.extend,因为对points变量的引用是硬编码的chart.html

在像 Backbone 这样的框架中,视图是嵌套的,因此我可以将内部小部件包装到更大的视图中,并在外部视图中定义数据转换的逻辑。我不太确定如何在 Ractive 中继续前进。也许我应该从一开始就以不同的方式设计小部件。

更一般地说,我的问题是我可以在 Ractive 中编写小组件,但我不太确定如何将它们组合成更大的东西。

Ractive 中专门化或扩展组件的惯用方式是什么?或者将许多组件组合成一个更大的应用程序?

4

1 回答 1

6

有几个可能的解决方案。我不确定什么是惯用的——一般来说,Ractive 的理念是“如果它有效,它就是正确的解决方案!” - 我是作者,但我会把它留给社区来决定什么是惯用的。

1. 初始化时传入函数

如果您使用 d3 创建散点图,通常您会执行以下操作:

d3.select( 'circle' ).data( points )
     .enter().append( 'circle' )
       .attr( 'cx', function ( d ) { return d.x; })
       .attr( 'cy', function ( d ) { return d.y; })
       .attr( 'r', 5 );

换句话说,对于每个基准在数组中的 item 中,我们提供了一个函数,该函数提取我们需要绘制其 x 和 y 位置的值。

Ractive 的等价物是在初始化组件时指定一个函数:

<!-- the template -->
<svg>
  <path d='{{ points_to_path(points) }}'/>
</svg>
// let's create a chart component that assumes we get an array
// of points with an `x` and a `y` property
var Chart = Ractive.extend({
  template: chart,
  data: {
    points_to_path: function(points) {
      // is there a 'normalise' function? If so, normalise
      // the data we've been given
      if ( var normalise = this.get( 'normalise' ) ) {
        points = points.map( normalise );
      }

      // turn a normalised `{x: x, y: y}` point into 'x,y'
      var pointToString = function ( point ) {
        return point.x + ',' + point.y;
      };

      // create the SVG path
      return 'M' + points.map( pointToString ).join( ' ' );
    }
  }
});

// now, we need to create a function that tells the Chart
// component how to deal with the data we're about to give it
var chart = new Chart({
  data: {
    points: [[1, 2], [3, 4], [5, 6]],
    normalise: function ( point ) {
      return { x: point[0], y: point[1] };
    }
  }
});

因此,如果您有一组带有datevalue属性的点,您只需传递一个返回的normalise函数(或者normalize如果您更喜欢美式拼写......){x: point.date, y: point.value}

(当然,points_to_path如果这样更容易,您可以改写整个函数。)

2.使用部分

另一种方法是在不同情况下使用不同的部分:

<!-- widget template -->
<h2>This is a widget</h2>
<div class='contains-dynamic-contents'>
  {{>inner}}
</div>
var widget = new Widget({
  el: 'widgetContainer',
  partials: {
    inner: '<p>This paragraph will appear inside the div</p>'
  }
});

这为您提供了很大的自由度,但折线图示例可能更难以适应。

内联组件

第一种方法也适用于内联组件- 此示例假设您使用的是开发(0.3.8-pre)版本,该版本即将发布:

Ractive.components.linechart = Chart;
<div class='application'>
  <h1>This is a chart</h1>
  <linechart points='{{someData}}' normalise='{{someNormaliseFunction}}'/>
</div>

(提示:您可以使用 . 指定默认normalise函数Chart.data.normalise = someFunction。)

第二种方法有点棘手 - 您必须在初始化时动态切换部分:

Chart = Ractive.extend({
  beforeInit: function () {
    this.partials.inner = ( someCondition ? thisPartial : thatPartial );
  },
  // ...
});

很抱歉这个回复太长了,希望你想要的答案在这里某个地方!

于 2013-12-10T23:20:09.977 回答