简体   繁体   English

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

[英]In Ember, how do I create a component that reacts to the action of another component?

I have a button-icon component that, when hovered over, will send a hoverIn and hoverOut action (example code so please forgive any errors): 我有一个button-icon组件,当盘旋时,将发送hoverInhoverOut操作(示例代码,所以请原谅任何错误):

app/components/button-icon/component.js: 应用/组件/按钮图标/ 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
});

app/components/button-icon/template.hbs: 应用/组件/按钮图标/ template.hbs:

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

I also have a button-tooltip component that should be displayed when the button is hovered over: 我还有一个button-tooltip组件,当按钮悬停时应显示该组件:

app/components/button-tooltip/component.js: 应用/组件/按钮工具提示/ component.js:

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

app/components/button-tooltip/template.hbs: 应用/组件/按钮工具提示/ template.hbs:

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

In my template, I'd like to use both like so: 在我的模板中,我想像这样使用两者:

app/index/template.hbs: 应用程序/索引/ 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}}

How do I get the button-icon to communicate with the button-tooltip so that the tooltip is shown when the icon is hovered over? 如何让button-iconbutton-tooltip进行通信,以便在图标悬停时显示工具提示? If I only had one button, I can bind both the button and tooltip to a property on the controller, but I have a variable list of them to display. 如果我只有一个按钮,我可以将按钮和工具提示绑定到控制器上的属性,但我有一个变量列表要显示。 I can also wrap both components in another component (called button-with-tooltip or something), but this seems like it's starting to get into component-ception. 我也可以将这两个组件包装在另一个组件中(称为button-with-tooltip或者其他东西),但这似乎已经开始进入组件构建。

It's pretty complicated to set such kind of interactions when you have that templates. 当你拥有这些模板时,设置这种交互非常复杂。 Your components are fully independent, but they should have a parent-child connection, since they are actually the parent and a child. 您的组件完全独立,但它们应该具有父子连接,因为它们实际上是父组件和子组件。

A more suitable approach for me is below. 对我来说更合适的方法如下。

app/index/template.hbs 应用程序/索引/ template.hbs

{{#buttons-list buttons=property_with_a_correct_list_from_the_index_controller}}

app/components/button-list/template.hbs 应用程序/组件/按钮列表/ template.hbs

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

app/components/button-icon/template.hbs 应用/组件/按钮图标/ template.hbs

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

app/components/button-icon/component.js: 应用/组件/按钮图标/ component.js:

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

  ...

});

app/components/button-tooltip/template.hbs: 应用/组件/按钮工具提示/ template.hbs:

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

app/components/button-tooltip/component.js: 应用/组件/按钮工具提示/ component.js:

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

And the property_with_a_correct_list_from_the_index_controller should look like this 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!'}}
]

Let's review it: 我们来看看吧:

  • I moved edged tags in the components to the controllers in a tagName property 我将组件中的edged标签移动到tagName属性中的控制器
  • A content of a tooltip now directed by the tooltip itself, not by the parent icon component 工具提示的内容现在由工具提示本身定向,而不是由父图标组件定向
  • Now a tooltip and an icon have clear relationship, so the icon finally has any reasonable way to control it 现在工具提示和图标有明确的关系,因此图标最终任何合理的方法来控制它

For now let's determine your high-level requirement for the sample: 现在让我们确定您对样本的高级要求:

  • User should see a tooltip when hovers an icon. 用户应该在悬停图标时看到工具提示。
  • User shouldn't see a tooltip when leaved an icon. 留下图标时,用户不应该看到工具提示。

As you can see the icon component totally controls the tooltip visibility. 如您所见,图标组件完全控制工具提示可见性。 In this case I'd consider an approach with conditional template. 在这种情况下,我会考虑使用条件模板的方法。 For example: 例如:

app/components/button-icon/component.js: 应用/组件/按钮图标/ 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
});

app/components/button-icon/template.hbs 应用/组件/按钮图标/ template.hbs

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

As you can see, your sample is rewritten in a more clear way, where you can see a approach to control tooltip visibility. 如您所见,您的样本以更清晰的方式重写,您可以在其中看到控制工具提示可见性的方法。 I'd recommend to use such approach only in case when you need to control the tooltip visibility. 我建议仅在需要控制工具提示可见性时才使用此方法。

Back to 回到

more code here to handle other stuff 这里有更多代码来处理其他内容

For this I would recommend to not discard your approach with binding of a property. 为此,我建议不要放弃绑定属性的方法。 Just create a property with a required state in the button-icon component and make a corresponding computed property in the button-tooltip component, which will be listening for changes in the property. 只需在button-icon组件中创建一个具有所需状态的属性,并在button-tooltip组件中创建相应的计算属性,该组件将侦听属性中的更改。

Example: 例:

app/components/button-icon/component.js: 应用/组件/按钮图标/ 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
});

app/components/button-icon/template.hbs 应用/组件/按钮图标/ template.hbs

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

app/components/button-tooltip/component.js: 应用/组件/按钮工具提示/ 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
});

PS But the first approach I like more %) PS但我喜欢的第一种方法更多%)

Once you are using a version of ember that supports yielding values in a component, I think this is 1.10.0, you can do the following, which is very intuitive. 一旦你使用支持在组件中产生值的ember版本,我认为这是1.10.0,你可以做到以下,这是非常直观的。

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

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

And in your button-icon component instead of sending an action up, you would set a value eg isActive , and send that down. 在您的button-icon组件中,您可以设置一个值,例如isActive ,然后将其发送下来。

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

The idea is actions up, data down. 这个想法是行动起来,数据下降。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM