我正在使用 ember 构建管理仪表板。我想创建一个可重用的图表对象,我可以在整个应用程序中拥有多个实例。图表对象应该有一个模板,该模板由一些标记和一个画布元素组成,在插入 DOM 后我需要其 id 以附加实际图表 (chart.js)。我尝试了几种方法,但我似乎无法找出正确的架构来做到这一点。
ember 中实现上述目标的正确架构是什么?
谢谢!
我正在使用 ember 构建管理仪表板。我想创建一个可重用的图表对象,我可以在整个应用程序中拥有多个实例。图表对象应该有一个模板,该模板由一些标记和一个画布元素组成,在插入 DOM 后我需要其 id 以附加实际图表 (chart.js)。我尝试了几种方法,但我似乎无法找出正确的架构来做到这一点。
ember 中实现上述目标的正确架构是什么?
谢谢!
Ember.Component
是你的朋友正如@raulbrito 已经提到的,如果你想要在 ember 中重用组件,最好的方法是使用新的Ember.Component
,它在很大程度上基于web 组件的新 w3 草案,因此是未来的证明。
我试图举一个简单的例子来说明如何实现这一点。给定一个简单route
的model
钩子返回一些静态数据的地方:
App.IndexRoute = Ember.Route.extend({
model: function(){
return Ember.Object.create({
modelOne: data,
modelTwo: data2
});
}
});
data
并且data2
只是为简单起见全局定义的静态对象(正如您将在演示中看到的那样),但这也可能是来自后端或固定装置等的数据。
然后在模板中插入带有线条的图表组件,{{line-chart data=model.modelOne}}
如您所见,我们还将data
属性设置为索引模型model.modelOne
或model.modelTwo
:
<script type="text/x-handlebars" id="index">
<h2>Chart one</h2>
{{line-chart data=model.modelOne}}
<h2>Chart two</h2>
{{line-chart data=model.modelTwo}}
</script>
我们的组件模板看起来很简单,因为它会渲染一个简单的canvas
元素,但它可以根据需要变得复杂,关于如何使用Ember.Component
请参阅文档:
<script type="text/x-handlebars" id="components/line-chart">
</script>
App.LineChartComponent = Ember.Component.extend({
tagName: 'canvas',
attributeBindings: ['width', 'height'],
width: '480',
height: '360',
data: null,
didInsertElement: function() {
var ctx = this.get('element').getContext("2d");
var myNewChart = new Chart(ctx).Line(this.get('data'));
}
});
注意命名在这里很重要,Ember 知道哪个子类根据其名称为组件提供动力。例如,如果您有一个名为 的组件line-chart
,您将创建一个名为 的子类App.LineChartComponent
。如果您的组件被调用bar-chart-simple
,则类名将是App.BarChartSimpleComponent
等等。Ember 将使用组件的驼峰化名称查找一个类,后跟Component
.
因此,由于Ember.Component
extends fromEmber.View
我们可以定义各种属性Ember.View
支持,例如tagName
. 在我们的例子中,我们使用canvas
,因为这是chart.js
需要工作的。正如你所看到的,我们还定义了一些attributeBindings
来控制内部 ember的width
和。该组件还定义了一个属性(可以称为任何您认为合适的名称),我们稍后在从钩子返回的模板中设置我们的模型数据。最后,在我们组件的钩子中,我们初始化图表,将数据对象传递给新创建的类。height
canvas
data
IndexRoute
model
didInsertElement
this.get('data')
Chart.js
var ctx = this.get('element').getContext("2d");
var myNewChart = new Chart(ctx).Line(this.get('data'));
最后但并非最不重要的一点是,请参阅此处以获取上述说明的工作示例。
希望能帮助到你。
我试图模拟model
钩子解析的延迟以模拟来自后端的响应,因为您可以看到模板渲染正在等待model
首先解决的承诺。基本上我所做的是使用Ember.run.later
2000ms 的延迟来解决一旦超时的承诺:
App.IndexRoute = Ember.Route.extend({
model: function(){
return new Ember.RSVP.Promise(function(resolve) {
Ember.run.later(function() {
var m = Ember.Object.create({
modelOne: data,
modelTwo: data2
});
resolve(m);
}, 2000);
});
}
});
只是为了好玩,我还添加了LoadingRoute
一个在承诺解析等待数据时显示微调器,这LoadingRoute
是 ember 的一个记录较少的功能,您可以在此处阅读更多信息:https ://gist.github.com/ machty/5647589在How do I put up a (global) Loading Spinner during a transition w/ Promises?
请在此处查看更新的示例:http: //jsbin.com/odosoy/145/edit
至于上面提到的LoadingRoute
@SamSelikoff 指出,它现在正式记录在案:http ://emberjs.com/guides/routing/defining-your-routes/#toc_initial-routes
我对此有一些想法,所以把它扔在那里,以防它帮助你。
首先,我建议您去观看 Sam Selikoff 关于将 Ember 与 D3 结合使用的演示文稿。所有信息都在这里: http: //www.samselikoff.com/blog/2013/08/09/ember-d3-simple-dashboards/。另外,不要错过博客文章的评论部分。
这是使用 Ember 视图包装 D3 对象的一个很好的示例,并且可以是一个很好的可重用解决方案。这里需要注意的是,Ember Views 需要一个提供数据的支持控制器。根据您希望在应用程序中重用图表的位置,这可能会带来不便。
另一种方法是使用 Ember 组件。在这种情况下,您只需要定义 Component 和关联的车把模板。它的好处是它不需要任何支持控制器,因此将您从依赖中解放出来,这可能使您更容易在应用程序的不同位置添加这样的组件。如果没有具体的例子,我认为很难得出一个很好的结论,但也许这会帮助你澄清事情。