在Ember中,如何创建对另一个组件的操作做出反应的组件?

时间:2015-04-18 23:53:00

标签: javascript ember.js

我有一个button-icon组件,当它悬停时,会发送hoverInhoverOut操作(示例代码请原谅任何错误):

  

应用/组件/按钮图标/ component.js:

export default Ember.Component.extend({
  didInsertElement: function() {
    // hover in
    this.$().hover(function() {
      this.sendAction('hoverIn');
    ,
    // hover out
    function() {
      this.sendAction('hoverOut');
    }
  },

  // more code here to handle other stuff
});
  

应用/组件/按钮图标/ template.hbs:

<button>{{yield}}</button>

我还有一个button-tooltip组件,当按钮悬停时应显示该组件:

  

应用/组件/按钮工具提示/ component.js:

export default Ember.Component.extend({
    // some code here to handle positioning
});
  

应用/组件/按钮工具提示/ template.hbs:

<div>{{yield}}</div>

在我的模板中,我想像这样使用两者:

  

应用程序/索引/ template.hbs:

{{#button-icon}}
  <div>Cat</div>
  {{#button-tooltip}}<img src="cat.png">{{/button-tooltip}}
{{/button-icon}}

{{#button-icon}}
  <div>Dog</div>
  {{#button-tooltip}}<img src="dog.png">{{/button-tooltip}}
{{/button-icon}}

{{#button-icon}}
  <div>Rat</div>
  {{#button-tooltip}}Nobody wants to see a picture of a rat!{{/button-tooltip}}
{{/button-icon}}

如何让button-iconbutton-tooltip进行通信,以便在图标悬停时显示工具提示?如果我只有一个按钮,我可以将按钮和工具提示绑定到控制器上的属性,但我有一个变量列表要显示。我也可以将这两个组件包装在另一个组件中(称为button-with-tooltip或其他),但这似乎已经开始进入组件构造。

2 个答案:

答案 0 :(得分:3)

当你拥有这些模板时,设置这种交互非常复杂。您的组件完全独立,但它们应该具有父子连接,因为它们实际上是父组件和子组件。

下面是一个更合适的方法。

  

应用程序/索引/ template.hbs

{{#buttons-list buttons=property_with_a_correct_list_from_the_index_controller}}
  

应用/组件/按钮列表/ template.hbs

{{#each button in buttons}}
  {{#button-icon data=button}}
{{/each}}
  

应用/组件/按钮图标/ template.hbs

<div>{{data.title}}</div>
{{#button-tooltip data=data.tooltip}}
  

应用/组件/按钮图标/ component.js:

export default Ember.Component.extend({
  tagName: 'button',

  ...

});
  

应用/组件/按钮工具提示/ template.hbs:

{{#if isPicture}}
  <img src={{data.image}} />
{{else}}
  {{data.text}}
{{/if}}
  

应用/组件/按钮工具提示/ component.js:

export default Ember.Component.extend({
  tagName: 'div'
  isPicture: function() {
    this.get('data.type') == 'image'
  }.property('data.type')
});

property_with_a_correct_list_from_the_index_controller看起来应该是这样的

[
  {title: 'Cat', tooltip: {isPicture: true, image: 'cat.png'}},
  {title: 'Dog', tooltip: {isPicture: true, image: 'dog.png'}},
  {title: 'Rat', tooltip: {isPicture: false, text: 'Nobody wants to see a picture of a rat!'}}
]

让我们回顾一下:

  • 我将组件中的edged标签移动到tagName属性
  • 中的控制器
  • 工具提示现在由工具提示本身指导的内容,而不是父图标组件
  • 现在工具提示和图标有明确的关系,所以图标最终 以任何合理的方式控制它

现在让我们确定您对样本的高级要求:

  • 用户在悬停图标时应看到工具提示。
  • 当留下图标时,用户不应该看到工具提示。

如您所见,图标组件完全控制工具提示的可见性。在这种情况下,我会考虑使用条件模板的方法。例如:

  

应用/组件/按钮图标/ component.js:

export default Ember.Component.extend({
  tagName: 'button',
  showTooltip: false,

  didInsertElement: function() {
    self = this // this will be redefined inside of hover function
    // hover in
    this.$().hover(function() {
      self.set('showTooltip', true);
    ,
    // hover out
    function() {
      self.set('showTooltip', false);
    }
  },

  // more code here to handle other stuff
});
  

应用/组件/按钮图标/ template.hbs

<div>{{data.title}}</div>
{{#if showTooltip}}
  {{#button-tooltip data=data.tooltip}}
{{/if}}

如您所见,您的示例将以更清晰的方式重写,您可以在其中看到控制工具提示可见性的方法。我建议仅在需要控制工具提示可见性的情况下使用此方法。

返回

  

此处有更多代码来处理其他内容

为此,我建议不要放弃绑定属性的方法。只需在button-icon组件中创建一个具有所需状态的属性,并在button-tooltip组件中创建相应的计算属性,该属性将监听属性中的更改。

示例:

  

应用/组件/按钮图标/ component.js:

export default Ember.Component.extend({
  tagName: 'button',
  tooltipProps: [],

  didInsertElement: function() {
    self = this // this will be redefined inside of hover function
    // hover in
    this.$().hover(function() { 
      self.get('tooltipProps').addObject('showIt');
    , function() { // hover out
      self.get('tooltipProps').removeObject('showIt');
    });
    this.$().on('click', function() {
      self.get('tooltipProps').addObject('makeitRed');
    });
  },

  // more code here to handle other stuff
});
  

应用/组件/按钮图标/ template.hbs

<div>{{data.title}}</div>
{{#button-tooltip data=data.tooltip props=tooltipProps}
  

应用/组件/按钮工具提示/ component.js:

export default Ember.Component.extend({
  tagName: 'div'
  isPicture: function() {
    this.get('data.type') == 'image'
  }.property('data.type'),

  onPropsChange: function() {
    if (this.get('props.makeItRed')) {
      // make it actually red directly by the own component code
    }
  }.observe('props') // an observer because you need to do actions here, if you want to change the internal state use a computed property
});

P.S。但第一种方法我更喜欢%)

答案 1 :(得分:0)

一旦你使用支持在组件中产生值的ember版本,我认为这是1.10.0,你可以做到以下,这是非常直观的。

{{#button-icon as |active|}}
  <div>Cat</div>

  {{#button-tooltip active=active}}
    <img src="cat.png">
  {{/button-tooltip}}
{{/button-icon}}

在您的button-icon组件中,而不是向上发送操作,您可以设置一个值,例如isActive,并将其发送下来。

<button>{{yield isActive}}</button>

这个想法是行动,数据下降。