javascript - Ember 上的点击事件

标签 javascript ember.js ember-bootstrap

我发现了 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}}

现在这是我的问题:

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

谢谢。

最佳答案

为学习 EmberJS 和发布漂亮、明确的问题干杯!

你的错误

  1. 切勿修改 node_modules/bower_components/ 文件夹中的代码。如果你真的需要猴子修补某些东西,你可以在初始化程序中完成。但是您的用例不需要猴子补丁。

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

  3. 这个调用是不正确的:

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

    问题如下:

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

    2. 您只是将一堆位置参数传递给组件。如果 ddm.link-to 支持接受一个 Action ,正确的调用应该是这样的:

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

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

    3. 不带引号的
    4. low_to_high 是对在当前范围内定义的属性的引用。您可能指的是字符串:"low_to_high"

  4. 切勿直接在模板中使用 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'}}>
    

问题的答案

  1. 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 中应用。

  1. 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 查询参数,在这种情况下,您可以通过转换到不同的查询参数来更改排序顺序。

  1. 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/

相关文章:

javascript - Ember js - 文件上传组件 - 在第二次尝试上传同一文件时强制触发更改事件

javascript - Ember.js:如何在选择帮助器上使用观察者来过滤内容?

ember.js - 使用 ember-bootstrap 自定义元素改变变更集字段值

javascript - 触发来自另一个模板的组件中的 Bootstrap 模式

javascript - HTML5 音频标签停止播放和下载

javascript - 在 redraw() 之后使用 jQuery 选择 highcharts DOM

javascript - Backbone : Order of models inside a collection

javascript - 如何在javascript中计算点值?

ember.js - Ember-data 模型计算值,返回值而不是 promise

twitter-bootstrap - 在 ember 3.8 中使用 Bootstrap