点击Ember上的事件



我发现了EmberJS,并开始将现有网站迁移到这个框架中。我遇到了一个基于Bootstrap的下拉列表的问题。这个问题实际上帮助我更好地理解了Ember的概念,但我仍然有一些问题。

我使用ember引导程序模块生成了这个下拉列表(以及其他内容),下面是代码应该是什么:

{{#bs-dropdown as |dd|}}
{{#dd.button}}
Sort by
{{/dd.button}}
{{#dd.menu as |ddm|}}
{{#ddm.item}}{{#ddm.link-to "index"}}Price low to high{{/ddm.link-to}}{{/ddm.item}}
{{#ddm.item}}{{#ddm.link-to "index"}}Price high to low{{/ddm.link-to}}{{/ddm.item}}
{{/dd.menu}}
{{/bs-dropdown}}

现在,我希望在用户单击其中一个项目时执行一些javascript代码。在检查了模块的文档后,我发现菜单项组件是在哪里定义的,并按如下方式编辑了它的代码:

export default Component.extend({
layout,
classNameBindings: ['containerClass'],
/* ... */
actions: {
// My addition
sortByPrice(param){
alert("sorting");
},
// End of the addition
toggleDropdown() {
if (this.get('isOpen')) {
this.send('closeDropdown');
} else {
this.send('openDropdown');
}
},
},
});

然后我更新了hbs文件如下:

{{#dd.menu as |ddm|}}
{{#ddm.item action "sortByPrice" low_to_high}}
{{#ddm.link-to "index"  action "sortByPrice" low_to_high}}
Prix croissant
{{/ddm.link-to}}
{{/ddm.item}}
{{/dd.menu}}

这不起作用,这就是为什么我也将*action*添加到link-to元素中,并在其组件文件中类似地声明了操作。

import LinkComponent from '@ember/routing/link-component';
export default LinkComponent.extend({
actions: {
sortByPrice(param){
alert("sorting");
console.log("sorting");
},
},
});

如您所见,*link-to*组件扩展了LinkComponent组件。我最终明白了,这个元素不可能像本线程中解释的那样以本机方式处理点击事件。

出于沮丧,我最终选择了一种不那么优雅的方法,这种方法仍然有效:

{{#bs-dropdown id="sort" as |dd|}}
{{#dd.button}}
Sort by
{{/dd.button}}
{{#dd.menu as |ddm|}}
{{#ddm.item action "sortByPrice" low_to_high}}
<a
class="dropdown-item"
onclick="sortByPrice('low_to_high'); return false;"
href="#"
>
Price low to high
</a>
{{/ddm.item}}
{{/dd.menu}}
{{/bs-dropdown}}

下面是我的问题:

  1. 为什么在Component文件和hbs文件上定义操作都不会改变结果
  2. 为什么LinkComponent不以本机方式处理单击事件?我知道一个链接应该将用户重定向到一个新页面(这仍然是有争议的),但DOM事件仍然被触发,所以Ember是否故意忽略它并选择不让开发人员处理它?我想知道这背后的逻辑
  3. 有比我的解决方案更好的方法吗

谢谢。

为学习EmberJS并发布一个漂亮、明确的问题而欢呼!

你的错误

  1. 永远不要修改node_modules/bower_components/文件夹中的代码。如果你真的需要对某个东西进行猴子补丁,你可以在初始化器中完成。但是您的用例不需要猴子补丁。

  2. 您试图在菜单项组件中定义操作,但在父模板中应用了该操作。必须在该父级的模板组件/控制器中定义该操作。

  3. 此调用不正确:

    {{#ddm.link-to "index"  action "sortByPrice" low_to_high}}
    

    以下是问题:

    1. ddm.link-to组件应该创建到另一个路由的链接。它似乎不支持将行动传递给它

    2. 您只是将一组位置参数传递给组件。如果ddm.link-to确实支持接受操作,那么正确的调用将如下所示:

      {{#ddm.link-to "index" argName=(action "sortByPrice" low_to_high)}}
      

      在这种情况下,"index"是位置参数,argName是命名参数。

    3. 不带引号的low_to_high是对当前作用域上定义的属性的引用。您可能指的是字符串:"low_to_high"

  4. 不要直接在模板中使用JS代码。这是你永远不应该做的Ember:

    <a onclick="sortByPrice('low_to_high'); return false;">
    

    相反,传递一个操作(在本地范围中定义:在组件或控制器中):

    <a onclick={{action 'sortByPrice' 'low_to_high'}}>
    

    onclick属性名称是可选的。没有属性定义的操作意味着onclick(如果需要将操作附加到不同的事件,则只需要提供属性名称):

    <a {{action 'sortByPrice' 'low_to_high'}}>
    

    为了使链接在浏览器中正确设置样式,需要href属性。但你不必向它传递值'#'。在老式应用程序中,哈希符号是必需的,以防止链接覆盖URL。Ember为您覆盖URL覆盖,因此您可以简单地传递一个空的href

    以下是最后的正确用法:

    <a href {{action 'sortByPrice' 'low_to_high'}}>
    

问题解答

  1. 为什么在Component文件和hbs文件上定义操作都不会改变结果

因为您在不同的范围中定义了它们。

如果在app/components/foo-bar.js中定义操作,则必须在app/templates/components/foo-bar.hbs中应用该操作。

如果在app/controllers/index.js中定义操作,则必须在app/templates/index.hbs中应用该操作。

  1. 为什么LinkComponent不以本机方式处理点击事件?我知道一个链接应该将用户重定向到一个新页面(这仍然是有争议的),但DOM事件仍然被触发,所以Ember是否故意忽略它并选择不让开发人员处理它?我想知道这背后的逻辑

在PWA中,您不执行实际的页面重定向。这样的重定向会重新加载整个应用程序。

相反,LinkComponent会覆盖点击并告诉Ember的路由系统执行转换。路由必须正确设置,并且传递给LinkComponent的路由必须存在。

您的目标似乎不是执行转换,而是更改变量,因此LinkComponent在此不适用。除非您将排序顺序属性关联到URL查询参数,在这种情况下,您可以通过转换到不同的查询参数来更改排序顺序。

  1. 有比我的解决方案更好的方法吗

有关使用ember-bootstrap下拉菜单的最简单方法,请参阅下面的内容。


一个工作示例

控制器:

export default Ember.Controller.extend({
isSortAccending: true,
actions: {
changeSortDirection (isSortAccending) {
this.set('isSortAccending', isSortAccending);
}
}
});

模板:

<p>
Current sort order:
{{if isSortAccending "ascending" "descending"}}
</p>
{{#bs-dropdown as |dd|}}
{{#dd.button}}
Sort by
{{/dd.button}}
{{#dd.menu as |ddm|}}
{{#ddm.item}}
<a href {{action "changeSortDirection" true}}>
Price high to low
</a>
{{/ddm.item}}
{{#ddm.item}}
<a href {{action "changeSortDirection" false}}>
Price high to low
</a>
{{/ddm.item}}
{{/dd.menu}}
{{/bs-dropdown}}

这是一个工作演示。

最新更新