如何在嵌套组件中处理 EmberJS 中的操作

How to handle action in EmberJS in nested Component

所以我在 EmberJS 中嵌套了组件,无法正确处理它们的操作。

我有路由 Create 并且在它的模板组件 pixel-grid:

<div class="row">
    <div class="col-sm-7">
        {{pixel-grid}}
    </div>
    <div class="col-sm-5">

    </div>
</div>

pixel-grid 模板中,我有一个名为 pixel-cell:

的组件
<table class="mx-auto">
    {{#each (range 0 panelWidth) as |row|}}
    <tr class="table-row">
        {{#each (range 0 panelHeight) as |cell|}}
        <th class="table-cell">
            {{pixel-cell onClick=(action 'changeColor')}}
        </th>
        {{/each}}
    </tr>
    {{/each}}
</table>

组件 pixel-cell 有一个空模板,因为我现在不需要它。在 pixel-cell 组件 js 文件中我有:

import Component from '@ember/component';
export default Component.extend({
    classNames: ['cell', 'clickable'],
    tagName: 'div',

    init() {
        this._super(...arguments);
    },
});

这段代码显然无法编译,因为我没有处理这个动作。 但是..

我试图在 pixel-cell 中设置操作,但后来 Ember 告诉我 pixel-grid 应该有那个操作。 所以我确实把这个 changeColor 动作放在 pixel-grid 中 -> 那是行不通的。

所以我尝试在 pixel-cell js:

中通过类似的方式来处理这个问题
click() {
    this.sendAction('changeColor');
},

-> 那行不通。

我不知道它应该如何工作;/我试图阅读指南,但仍然无法做到。请帮忙。

好的,所以我确实设法让它工作了。它看起来像这样:

pixel-grid 模板:

<table class="mx-auto">
    {{#each (range 0 panelWidth) as |row|}}
    <tr class="table-row">
        {{#each (range 0 panelHeight) as |cell|}}
        <th class="table-cell">
            {{pixel-cell}}
        </th>
        {{/each}}
    </tr>
    {{/each}}
</table>

pixel-cell组件js文件:

import Component from '@ember/component';
export default Component.extend({
    classNames: ['cell', 'clickable'],
    tagName: 'div',

    click: function () {
        this.sendAction('changeColor', this);
    },

    changeColor(cell) {
        console.log("CELL ACTION");
        console.log(cell);
        cell.element.style.backgroundColor = 'red';
    }
});

其他文件为空(pixel-gridjs文件中只有panelHeight和panel Width)。 这是执行此操作的好方法吗?

我个人从未使用过sendAction。相反,您应该将操作作为属性从父组件传递给子组件,然后在子组件中调用它们。这种方法更容易推理以及 https://emberigniter.com/send-closure-actions-up-data-owner/ 详细解释的其他好处。

在你的例子中:

像素-grid.js:

export default Component.extend({
  actions: {
    changeColor(cell) {
      console.log("CELL ACTION");
      console.log(cell);
      cell.style.backgroundColor = 'red';
    }
  }
});

像素-grid.hbs:

{{pixel-cell handleColorChange=(action 'changeColor')}}

像素-cell.js:

export default Component.extend({
    classNames: ['cell', 'clickable'],
    tagName: 'div',

    click: function () {
        // Invoke parent action and pass this element as the argument
        this.get("handleColorChange")(this.element);
    }
});

https://ember-twiddle.com/e04e318489bcc8e9e921e849c9fb9e9e?openFiles=templates.components.pixel-cell.hbs%2Ctemplates.components.pixel-grid.hbs

我创建了一个 twiddle 来向您展示从父组件传递到子组件的示例操作。可以参考上面的url更容易理解

我没有使用 sendAction,而是使用了一个称为关闭操作的概念,这是 Ember 未来的规范。

我建议不要处理组件元素上的操作。而是始终使用关闭操作!

如果你做{{some-component onClick=(action 'changeColor')}}你需要相应的动作changeColor不是里面的some-component!但是你可能想像这样在 some-component 中使用它:

<button onclick={{@changeColor}}>...</button>

在你的情况下,我会为 pixel-cell 组件设置 tagName: '' 并添加此模板:

<div onclick={{@changeColor}}></div>