【问题标题】:Ember.js: sending actions to components?Ember.js:向组件发送操作?
【发布时间】:2015-08-17 04:04:35
【问题描述】:

我有一个用于 Ember 组件的 mixin,名为 in-view,它的工作是请求将元素显示在视图中。它提供了一个属性,其值是要显示的一段内容,如果该属性与组件的内容匹配,那么我调用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, 

这很好用。当我想更改视图中的项目时,我遇到了这个问题。我可以让in-view mixin 观察inviewItem 属性:

}.on('didInsertElement').observes('inViewItem')

这也有效,但似乎有点代码味道。

另外,我的实际代码结构是有一个控制器知道哪个项目应该在视图中,然后它的模板调用一个my-item-list组件,该组件显示包含项目列表的可滚动div,并且在转而调用my-item 组件。这意味着我必须将控制器中的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 中。相反,我可以将控制器属性的 name 传递给组件以进行观察,但这似乎过于笨拙,而且观察名称可变的属性也很棘手。更重要的是,我认为当控制器在 2.0 中消失时这将不起作用。

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

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

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

【问题讨论】:

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

标签: ember.js


【解决方案1】:

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

有些人使用滚动服务来跟踪和改变状态,我自己使用了几种变体。

听起来好像您正在处理一个可滚动的列表,可能是一个 div,并且视图中的项目不仅仅是页面状态的函数,而且可能会以编程方式发生变化。例如,插入了一个新项目,您想将新项目滚动到视图中。

一个像 jquery.scrollTo 或类似的插件(统称为“滚动”)会比简单地跳转到新位置更好,因为它保留了用户对他们在页面上的位置的上下文意识。

使用可滚动的 div 或列表或类似内容,您可以选择让顶级组件控制滚动状态。在这种情况下,滚动状态仍然是本地化的,但不是本地化到每个项目,而是本地化到整个可滚动区域,这是它更好的归属。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-07
    • 1970-01-01
    • 2015-09-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多