使用Ember,mixin检测视图/组件外部的单击

时间:2015-06-03 14:49:59

标签: ember.js

我正在编写一个Mixin来处理用户在视图/组件外部点击的时间。

这是mixin:

App.ClickElsewhereMixin = Ember.Mixin.create({

  onClickElsewhere: Ember.K,

  didRender: function() {
    this._super.apply(this, arguments);
    return $(document).on('click', this.get('onClickElsewhere'));
  },

  willDestroyElement: function() {
    this._super.apply(this, arguments);
    $(document).off('click', this.get('onClickElsewhere'));
  },
});

我在我的组件中使用它:

onClickElsewhere: function() {
    this.send('exitEditMode');
},

但是当我运行它时,我得到了:

TypeError: this.send is not a function

如何保留this上下文?

解决方案:

只是为了让读者更容易,在这里工作的Mixin:

App.ClickElsewhereMixin = Ember.Mixin.create({

  onClickElsewhere: Ember.K,

  setupListener: Ember.on('didRender', function() {
    // Set an event that will be fired when user clicks outside of the component/view
    return $(document).on('click', $.proxy(this.get('onClickElsewhere'), this));
  }),

  removeListener: Ember.on('willDestroyElement', function() {
    // Clean the previously defined event to keep events stack clean
    return $(document).off('click', $.proxy(this.get('onClickElsewhere'), this));
  }),
});

5 个答案:

答案 0 :(得分:7)

当前的答案并不检查点击是否实际位于元素之外 - 单击该组件也会触发回调。

这是一个更新版本:

export default Ember.Mixin.create({
  onOutsideClick: Ember.K,

  handleOutsideClick: function(event) {
    let $element = this.$();
    let $target = $(event.target);

    if (!$target.closest($element).length) {
      this.onOutsideClick();
    }
  },

  setupOutsideClickListener: Ember.on('didInsertElement', function() {
    let clickHandler = this.get('handleOutsideClick').bind(this);

    return Ember.$(document).on('click', clickHandler);
  }),

  removeOutsideClickListener: Ember.on('willDestroyElement', function() {
    let clickHandler = this.get('handleOutsideClick').bind(this);

    return Ember.$(document).off('click', clickHandler);
  })
});

答案 1 :(得分:6)

Greg回答有错误,这使得删除clickHandler事件无法正常工作。这意味着即使您销毁组件,您的clickevent也会触发。

这是正确的版本

import Ember from 'ember';

export default Ember.Mixin.create({
    onOutsideClick: Ember.K,

  handleOutsideClick: function(event) {
    let $element = this.$();
    let $target = $(event.target);

    if (!$target.closest($element).length) {
      this.onOutsideClick();
    }
  },

  setupOutsideClickListener: Ember.on('didInsertElement', function() {

    let clickHandler = this.get('handleOutsideClick').bind(this);

    return Ember.$(document).on('click', clickHandler);
  }),

  removeOutsideClickListener: Ember.on('willDestroyElement', function() {

    let clickHandler = this.get('handleOutsideClick').bind(this);

    return Ember.$(document).off('click', Ember.run.cancel(this, clickHandler));
  })
});

答案 2 :(得分:4)

执行此操作的方法是Ember.run.bind。这需要处理绑定和运行循环。

App.ClickElsewhereMixin = Ember.Mixin.create({

  onClickElsewhere: Ember.K,

  setupListener: Ember.on('didRender', function() {
    this.set('clickHandler', Ember.run.bind(this, this.onClickElsewhere));
    Ember.$(document).click(this.get('clickHandler'));
  }),

  removeListener: Ember.on('willDestroyElement', function() {
    Ember.$(document).off('click', this.get('clickHandler'));
  }),
});

答案 3 :(得分:2)

您有两种选择:

  1. 使用closure
  2. 使用bind
  3. 封闭

    App.ClickElsewhereMixin = Ember.Mixin.create({
    
      onClickElsewhere: Ember.K,
    
      didRender: function() {
        this._super.apply(this, arguments);
        return $(document).on('click', function(this){ return this.get('onClickElsewhere'); }(this));
      },
    
      willDestroyElement: function() {
        this._super.apply(this, arguments);
        $(document).off('click', function(this){ return this.get('onClickElsewhere'); }(this));
      },
    });
    

    绑定

    App.ClickElsewhereMixin = Ember.Mixin.create({
    
      onClickElsewhere: Ember.K,
    
      didRender: function() {
        this._super.apply(this, arguments);
        return $(document).on('click', this.get('onClickElsewhere').bind(this));
      },
    
      willDestroyElement: function() {
        this._super.apply(this, arguments);
        $(document).off('click', this.get('onClickElsewhere').bind(this));
      },
    });
    

    但是,并非所有浏览器都支持绑定。

    另外,我认为您需要在组件中使用sendAction而不是sendhttp://guides.emberjs.com/v1.10.0/components/sending-actions-from-components-to-your-application/

    修改

    jQuery.proxy在封面下使用call / apply。有关call / applybind的讨论,请参阅this post

答案 4 :(得分:1)

您可以使用lib ember-click-outside。为我工作。