【问题标题】:Ember, mixin to detect click outside of view/componentEmber,mixin 来检测视图/组件之外的点击
【发布时间】:2015-06-03 14:49:59
【问题描述】:

我正在编写一个 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));
  }),
});

【问题讨论】:

    标签: ember.js


    【解决方案1】:

    当前答案不会检查点击是否真的在元素之外——点击组件也会触发回调。

    这是一个更新的版本:

    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);
      })
    });
    

    【讨论】:

    • 所以这实际上不会正确删除监听器,在每个函数中执行 this.get(...).bind(this) 会创建对 不同 函数的引用,因此 document.off(...) 不会正确识别监听器.它应该存储对绑定函数的引用并在添加/删除中使用相同的引用
    【解决方案2】:

    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));
      })
    });
    

    【讨论】:

    • 非常感谢您的解决方案对我有用。我认为问题在于我没有这样做。get('clickHandler')
    【解决方案3】:

    ember 的做法是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'));
      }),
    });
    

    【讨论】:

      【解决方案4】:

      你有两个选择:

      1. 使用closure
      2. 使用bind

      关闭

      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 而不是send (http://guides.emberjs.com/v1.10.0/components/sending-actions-from-components-to-your-application/)

      编辑

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

      【讨论】:

      • 其实我发现可以使用jQuery的$.proxy函数,你觉得呢?
      • 谢谢!看起来有很多方法。
      • 这不起作用,因为执行bind 会创建对两个不同函数的引用,而removeEventListener 无法正确匹配它们。
      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-02
        • 1970-01-01
        • 2013-09-24
        • 2017-02-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多