Ember.js:向组件发送操作?

Ember.js:向组件发送操作?,ember.js,Ember.js,我有一个Ember组件的mixin,在视图中名为,,其任务是请求将元素引入视图。它提供了一个属性,该属性的值是要显示的一段内容,如果该属性与组件的内容匹配,则我调用scrollIntoView或类似的属性。代码如下所示: // calling template {{#each items as |item|}} {{my-item content=item inViewItem=inViewItem}} }} // mixins/in-view.js scrollIntoView() {

我有一个Ember组件的mixin,在视图中名为
,其任务是请求将元素引入视图。它提供了一个属性,该属性的值是要显示的一段内容,如果该属性与组件的内容匹配,则我调用
scrollIntoView
或类似的属性。代码如下所示:

// calling template
{{#each items as |item|}}
   {{my-item content=item inViewItem=inViewItem}}
}}

// mixins/in-view.js
scrollIntoView() {
  if (this.get('content') === this.get('inViewItem'))
    this.get('element').scrollIntoView();
}.on('didInsertElement')

// components/my-item/component.js
import InView from 'mixins/in-view';
export default Ember.Component.extend(InView, 
这个很好用。当我想更改视图中的项目时,我遇到了一个问题。我可以让视图中的
混合观察
inviewItem
属性:

}.on('didInsertElement').observes('inViewItem')
这也行,但似乎有点代码味道

此外,我的实际代码结构是,有一个控制器,它知道哪个项目应该在视图中,然后它的模板调用一个
myitemlist
组件,该组件显示包含项目列表的可滚动div,然后调用
myitem
组件。这意味着我必须将
inViewItem
属性从控制器向下传递到两个级别,如

// resource/controller.js
inViewItem: something

// resource/template.js
{{my-item-list items=item inViewItem=inViewItem}}

// components/my-item-list/template.js
{{#each items as |item|}}
   {{my-item content=item inViewItem=inViewItem}}
}}
我可以通过将
my item
模板硬连接到控制器上的
inViewItem
属性来避免这种情况:

scrollIntoView() {
  if (this.get('content') === this.get('controller.inViewItem'))
    this.get('element').scrollIntoView();
}.on('didInsertElement')
但这是另一种代码气味;我不想在mixin中构建对特定控制器字段的这种依赖。相反,我可能会将控制器属性的名称传递给组件进行观察,但这似乎过于笨拙,而且观察名称为变量的属性也很棘手。更重要的是,我认为当控制器在2.0中消失时,这将不起作用

本质上,我想要的是一种“ping”或以某种方式向模板发送消息的方法。我知道原则上这违反了DDAU原则,但在这种特殊情况下,我需要的恰恰是以某种方式发送一个“动作下降”——一个动作告诉组件调整自身,使其进入视野

当然,我可以放弃视图中的
mixin的整个想法,只需让控制器深入到生成的HTML中,找到要显示的项目,并直接在其上发布
scrollIntoView
。然而,这似乎违反了一些分离关注点的原则;
my item
模板将不再完全控制自己


对于这种情况,推荐的设计模式是什么?

这里的解决方案是朝与您相反的方向发展。您的组件在这里是一个本地化的作用域,您感到的痛苦是,您的本地化作用域需要访问和更改全局状态(应用程序的滚动位置)

有些人使用滚动服务来跟踪和改变状态,我自己也使用过一些变体

听起来好像您正在处理一个可滚动的列表,可能是一个div,并且视图中的项目不仅仅是页面状态的函数,还可以通过编程方式进行更改。例如,插入了一个新项目,您希望将该新项目滚动到视图中

类似jquery.scrollTo或类似的插件(统称为“scroller”)比简单地跳转到新位置更好,因为它保留了用户对页面位置的上下文感知

使用可滚动的div或list或类似工具,您可以选择让顶级组件控制滚动状态。在本例中,滚动状态仍然是本地化的,但它不是本地化到每个项目,而是作为一个整体本地化到可滚动区域,这是它更好的归属


列表项在父列表组件中注册的模式有很多。在健壮的场景中,我可能会这样做,但一种快速且不太脏的方法是,在
didInsertElement
上,新的子元素向父元素发出包含其上下文的操作,然后,父控制器使用它来检查它是否是活动项,如果是,则触发scrollTo。

创建一个服务来在组件和父控制器之间共享数据怎么样?这可能不是服务的最佳使用,但它将消除尝试向下发送操作的需要。啊,runspired,比我先这么做。