我发现了 EmberJS 并开始将现有网站迁移到此框架。我在使用基于 Bootstrap 的下拉菜单时遇到问题。这个问题实际上帮助我更好地理解了 Ember 的概念,但我仍然有一些疑问。
我使用了 ember-bootstrap模块来生成这个下拉菜单(除其他外),代码应该是这样的:
{{#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 代码。检查后the module's documentation , 我找到了 menu item 组件的定义位置,并将其代码编辑如下:
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 组件。我最终明白这个元素不可能本地处理点击事件,如 this thread 中所述。 .
出于沮丧,我最终采用了一种不太优雅的方法,但仍然可以解决问题:
{{#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}}
现在这是我的问题:
- 为什么在组件文件和 hbs 上定义操作没有改变结果?
- 为什么 LinkComponent 本身不处理点击事件?我知道一个链接应该将用户重定向到一个新页面(这仍然是有争议的),但是 DOM 事件仍然被触发,那么 Ember 是否故意忽略它并选择不让开发人员处理它?我想知道这背后的逻辑。
- 有没有比我的解决方案更好的方法?
谢谢。
最佳答案
为学习 EmberJS 和发布漂亮、明确的问题干杯!
你的错误
切勿修改
node_modules/
和bower_components/
文件夹中的代码。如果你真的需要猴子修补某些东西,你可以在初始化程序中完成。但是您的用例不需要猴子补丁。您试图在菜单项组件中定义一个操作,但您在父模板中应用了它。该操作必须在该父级的模板组件/ Controller 中定义。
这个调用是不正确的:
{{#ddm.link-to "index" action "sortByPrice" low_to_high}}
问题如下:
ddm.link-to
组件应该创建到另一个路由的链接。它似乎不支持将 Action 传递给它。您只是将一堆位置参数传递给组件。如果
ddm.link-to
支持接受一个 Action ,正确的调用应该是这样的:{{#ddm.link-to "index" argName=(action "sortByPrice" low_to_high)}}
在这种情况下,
"index"
是位置参数,argName
是命名参数。
不带引号的 low_to_high
是对在当前范围内定义的属性的引用。您可能指的是字符串:"low_to_high"
。
切勿直接在模板中使用 JS 代码。这是你在 Ember 中永远不应该做的:
<a onclick="sortByPrice('low_to_high'); return false;">
相反,传递一个 Action (在本地范围内定义:在组件或 Controller 中):
<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'}}>
问题的答案
- Why is it that defining actions on both the Component file and the hbs one didn't change the result?
因为您在不同的范围内定义了它们。
如果您在 app/components/foo-bar.js
中定义一个 Action ,则该 Action 必须在 app/templates/components/foo-bar.hbs
中应用.
如果您在 app/controllers/index.js
中定义一个 Action ,则该 Action 必须在 app/templates/index.hbs
中应用。
- Why doesn't the
LinkComponent
handle click events natively? I get that a link is supposed to redirect users to a new page (which is still arguable), but the DOM event is still fired, so does Ember deliberately ignore it and choose not to let developers handle it? I want to know the logic behind this.
在 PWA 中,您不会进行实际的页面重定向。这样的重定向会重新加载整个应用。
相反,LinkComponent
会覆盖点击并告诉 Ember 的路由系统执行转换。必须正确设置路由,并且传递给 LinkComponent
的路由必须存在。
您的目标似乎不是执行转换而是更改变量,因此 LinkComponent
不适用于此处。除非您将排序顺序属性连接到 URL 查询参数,在这种情况下,您可以通过转换到不同的查询参数来更改排序顺序。
- Is there a better approach than my solution?
请参阅下文,了解使用 ember-bootstrap
下拉列表的最简单方法。
一个工作示例
Controller :
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}}
这是一个 working demo .
关于javascript - Ember 上的点击事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52435681/