Javascript 访问事件调用的组件方法内的组件属性

Javascript 访问事件调用的组件方法内的组件属性,javascript,jquery,ember.js,components,Javascript,Jquery,Ember.js,Components,我有一个组件,可以在单击窗口的任何位置时进行切换 为了实现这一点,我将组件方法作为全局事件绑定到body元素 此外,我需要访问组件方法中的组件属性,该属性由绑定到body元素的click事件调用 但它不起作用: app/components/example component.js: import Ember from 'ember'; export default Ember.Component.extend({ exampleProperty: 'example value',

我有一个组件,可以在单击窗口的任何位置时进行切换

为了实现这一点,我将组件方法作为全局事件绑定到
body
元素

此外,我需要访问组件方法中的组件属性,该属性由绑定到
body
元素的click事件调用

但它不起作用:

app/components/example component.js:

import Ember from 'ember';

export default Ember.Component.extend({

  exampleProperty: 'example value',

  didInsertElement() {
    console.log('start didInsertElement() ************************************************************');
    console.log('- "this" is the Ember.js component:');
    console.log(this.$());
    console.log('- "this.exampleProperty" has the Ember.js component value:');
    console.log(this.exampleProperty);
    Ember.$('body').click(this.exampleMethod).click();
    console.log('end didInsertElement() ************************************************************');
  },
  exampleMethod(event) {
    console.log('start exampleMethod() ************************************************************');
    console.log('- "this" is the DOM element that has triggered the event:');
    console.log(Ember.$(this));
    // console.log(this.$()); This doesn't work
    console.log('- "this.exampleProperty" is undefined:');
    console.log(this.exampleProperty);
    console.log('end exampleMethod() ************************************************************');
  },
});
import Ember from 'ember';

export default Ember.Component.extend({

  exampleProperty: 'example value',

  didInsertElement() {
    console.log('start didInsertElement() ************************************************************');
    console.log('- "this" is the Ember.js component:');
    console.log(this.$());
    console.log('- "this.exampleProperty" has the Ember.js component value:');
    console.log(this.exampleProperty);
    Ember.$('body').click(this, this.exampleMethod).click();
    console.log('end didInsertElement() ************************************************************');
  },
  exampleMethod(event) {
    console.log('start exampleMethod() ************************************************************');
    console.log('- "this" is the DOM element that has triggered the event:');
    console.log(Ember.$(this));
    // console.log(this.$()); This doesn't work
    console.log('- "this.exampleProperty" is undefined:');
    console.log(this.exampleProperty);
    console.log('- To access the component\'s "this.exampleProperty" the event data must be used:');
    const exampleComponent = event.data;
    console.log(exampleComponent.exampleProperty);
    console.log('end exampleMethod() ************************************************************');
  },
});
import Ember from 'ember';

export default Ember.Component.extend({

  exampleProperty: 'example value',

  didInsertElement() {    
    this._super(...arguments);
    // create a new function with 'this' as bound argument
    this.exampleMethod = this.exampleMethod.bind(this);
    // bind exampleMethod() function to event without arguments
    Ember.$('body').click(this, this.exampleMethod).click();
  },
  willDestroyElement() {
    this._super(...arguments);
    // unbind exampleMethod() function from event successfully without arguments
    Ember.$('body').off('click', this.exampleMethod);
  },
  exampleMethod() {
    // inside exampleMethod() 'this' is the Ember.js component 
    // as bound before, not the DOM element that has triggered the event
    console.log('Ember.js property: ", this.get('exampleProperty')); 
  },
});
// bind() creates a new function which here is anonymous
Ember.$('body').click(this, this.exampleMethod.bind(this));
// this.exampleMethod() is not the former anonymous function
Ember.$('body').off('click', this.exampleMethod);
// here things are worse as a new anonymous function is created
Ember.$('body').off('click', this.exampleMethod.bind(this));

如何让它工作?

我有一个可行的解决方案,但我觉得它不是很优雅

Ember.js组件必须作为事件数据传递给回调函数:

app/components/example component.js:

import Ember from 'ember';

export default Ember.Component.extend({

  exampleProperty: 'example value',

  didInsertElement() {
    console.log('start didInsertElement() ************************************************************');
    console.log('- "this" is the Ember.js component:');
    console.log(this.$());
    console.log('- "this.exampleProperty" has the Ember.js component value:');
    console.log(this.exampleProperty);
    Ember.$('body').click(this.exampleMethod).click();
    console.log('end didInsertElement() ************************************************************');
  },
  exampleMethod(event) {
    console.log('start exampleMethod() ************************************************************');
    console.log('- "this" is the DOM element that has triggered the event:');
    console.log(Ember.$(this));
    // console.log(this.$()); This doesn't work
    console.log('- "this.exampleProperty" is undefined:');
    console.log(this.exampleProperty);
    console.log('end exampleMethod() ************************************************************');
  },
});
import Ember from 'ember';

export default Ember.Component.extend({

  exampleProperty: 'example value',

  didInsertElement() {
    console.log('start didInsertElement() ************************************************************');
    console.log('- "this" is the Ember.js component:');
    console.log(this.$());
    console.log('- "this.exampleProperty" has the Ember.js component value:');
    console.log(this.exampleProperty);
    Ember.$('body').click(this, this.exampleMethod).click();
    console.log('end didInsertElement() ************************************************************');
  },
  exampleMethod(event) {
    console.log('start exampleMethod() ************************************************************');
    console.log('- "this" is the DOM element that has triggered the event:');
    console.log(Ember.$(this));
    // console.log(this.$()); This doesn't work
    console.log('- "this.exampleProperty" is undefined:');
    console.log(this.exampleProperty);
    console.log('- To access the component\'s "this.exampleProperty" the event data must be used:');
    const exampleComponent = event.data;
    console.log(exampleComponent.exampleProperty);
    console.log('end exampleMethod() ************************************************************');
  },
});
import Ember from 'ember';

export default Ember.Component.extend({

  exampleProperty: 'example value',

  didInsertElement() {    
    this._super(...arguments);
    // create a new function with 'this' as bound argument
    this.exampleMethod = this.exampleMethod.bind(this);
    // bind exampleMethod() function to event without arguments
    Ember.$('body').click(this, this.exampleMethod).click();
  },
  willDestroyElement() {
    this._super(...arguments);
    // unbind exampleMethod() function from event successfully without arguments
    Ember.$('body').off('click', this.exampleMethod);
  },
  exampleMethod() {
    // inside exampleMethod() 'this' is the Ember.js component 
    // as bound before, not the DOM element that has triggered the event
    console.log('Ember.js property: ", this.get('exampleProperty')); 
  },
});
// bind() creates a new function which here is anonymous
Ember.$('body').click(this, this.exampleMethod.bind(this));
// this.exampleMethod() is not the former anonymous function
Ember.$('body').off('click', this.exampleMethod);
// here things are worse as a new anonymous function is created
Ember.$('body').off('click', this.exampleMethod.bind(this));
给你钱

虽然这是一个有效的解决方案,但我发现它既丑陋又不切实际。因此,如果你有更好的方法,请张贴


我发现还有其他更糟糕的选项,比如将组件属性传递给事件数据,而不是整个组件,但是如果更新属性,则事件数据不会得到更改。

不确定它是否提供了您想要的更干净的方法,但是
.bind(this)
可能会有所帮助

// Using bind:
Ember.$('body').click(this, this.exampleMethod.bind(this)).click();

// Results in the below working as you desire:
this.$(); //returns jQuery.fn.init [div#ember256.ember-view, context: div#ember256.ember-view]

Ember.get(this, 'exampleProperty'); //returns 'example value'

每个组件都有
click
处理程序,只要单击组件,就会调用它。但在您的例子中,您希望在单击
body
元素时触发组件方法,因此您的方法是可行的。但唯一缺少的是
bind
和清除事件

import Ember from 'ember';

export default Ember.Component.extend({

  exampleProperty: 'example value',
  exampleMethodHandler: null,

   init() {
        this._super(...arguments);
        //bind function will return the function with scope changed to this.
        this._exampleMethodHandler = Ember.run.bind(this, this.exampleMethod);
    },

  didInsertElement() {    
        this._super(...arguments);
        Ember.$('body').on('click', this._exampleMethodHandler);
  },
   willDestroyElement() {
        this._super(...arguments);
        //Need to clear the registered event handler.
        if (this._exampleMethodHandler) {
            Ember.$('body').off('click', this._exampleMethodHandler);
        }
    },
  exampleMethod() {
    //Here this will refers to component,
    console.log('ComponentProperty access as usual ",this.get('exampleProperty'),event); 
  },
});
注意:我缓存了bind函数返回的函数引用,因为我们需要提供完全相同的引用来进行分解

所以


由于两个引用不同,上面的内容不会删除附加的事件处理程序。

我想提供一个完整的示例,在后面加上
bind()
,但不加上,并避免使用额外的处理程序对象,如
exampleMethodHandler

app/components/example component.js:

import Ember from 'ember';

export default Ember.Component.extend({

  exampleProperty: 'example value',

  didInsertElement() {
    console.log('start didInsertElement() ************************************************************');
    console.log('- "this" is the Ember.js component:');
    console.log(this.$());
    console.log('- "this.exampleProperty" has the Ember.js component value:');
    console.log(this.exampleProperty);
    Ember.$('body').click(this.exampleMethod).click();
    console.log('end didInsertElement() ************************************************************');
  },
  exampleMethod(event) {
    console.log('start exampleMethod() ************************************************************');
    console.log('- "this" is the DOM element that has triggered the event:');
    console.log(Ember.$(this));
    // console.log(this.$()); This doesn't work
    console.log('- "this.exampleProperty" is undefined:');
    console.log(this.exampleProperty);
    console.log('end exampleMethod() ************************************************************');
  },
});
import Ember from 'ember';

export default Ember.Component.extend({

  exampleProperty: 'example value',

  didInsertElement() {
    console.log('start didInsertElement() ************************************************************');
    console.log('- "this" is the Ember.js component:');
    console.log(this.$());
    console.log('- "this.exampleProperty" has the Ember.js component value:');
    console.log(this.exampleProperty);
    Ember.$('body').click(this, this.exampleMethod).click();
    console.log('end didInsertElement() ************************************************************');
  },
  exampleMethod(event) {
    console.log('start exampleMethod() ************************************************************');
    console.log('- "this" is the DOM element that has triggered the event:');
    console.log(Ember.$(this));
    // console.log(this.$()); This doesn't work
    console.log('- "this.exampleProperty" is undefined:');
    console.log(this.exampleProperty);
    console.log('- To access the component\'s "this.exampleProperty" the event data must be used:');
    const exampleComponent = event.data;
    console.log(exampleComponent.exampleProperty);
    console.log('end exampleMethod() ************************************************************');
  },
});
import Ember from 'ember';

export default Ember.Component.extend({

  exampleProperty: 'example value',

  didInsertElement() {    
    this._super(...arguments);
    // create a new function with 'this' as bound argument
    this.exampleMethod = this.exampleMethod.bind(this);
    // bind exampleMethod() function to event without arguments
    Ember.$('body').click(this, this.exampleMethod).click();
  },
  willDestroyElement() {
    this._super(...arguments);
    // unbind exampleMethod() function from event successfully without arguments
    Ember.$('body').off('click', this.exampleMethod);
  },
  exampleMethod() {
    // inside exampleMethod() 'this' is the Ember.js component 
    // as bound before, not the DOM element that has triggered the event
    console.log('Ember.js property: ", this.get('exampleProperty')); 
  },
});
// bind() creates a new function which here is anonymous
Ember.$('body').click(this, this.exampleMethod.bind(this));
// this.exampleMethod() is not the former anonymous function
Ember.$('body').off('click', this.exampleMethod);
// here things are worse as a new anonymous function is created
Ember.$('body').off('click', this.exampleMethod.bind(this));
bind()
函数创建一个新的绑定函数(BF)。ABF是一个 外来函数对象(来自ECMAScript 2015的术语),用于包装 原始函数对象。调用BF通常会导致 执行其包装函数

因此,如果使用
bind()
创建了一个新函数,那么如果它是匿名使用的,以后就不能重新引用它。因此,这不起作用:

import Ember from 'ember';

export default Ember.Component.extend({

  exampleProperty: 'example value',

  didInsertElement() {
    console.log('start didInsertElement() ************************************************************');
    console.log('- "this" is the Ember.js component:');
    console.log(this.$());
    console.log('- "this.exampleProperty" has the Ember.js component value:');
    console.log(this.exampleProperty);
    Ember.$('body').click(this.exampleMethod).click();
    console.log('end didInsertElement() ************************************************************');
  },
  exampleMethod(event) {
    console.log('start exampleMethod() ************************************************************');
    console.log('- "this" is the DOM element that has triggered the event:');
    console.log(Ember.$(this));
    // console.log(this.$()); This doesn't work
    console.log('- "this.exampleProperty" is undefined:');
    console.log(this.exampleProperty);
    console.log('end exampleMethod() ************************************************************');
  },
});
import Ember from 'ember';

export default Ember.Component.extend({

  exampleProperty: 'example value',

  didInsertElement() {
    console.log('start didInsertElement() ************************************************************');
    console.log('- "this" is the Ember.js component:');
    console.log(this.$());
    console.log('- "this.exampleProperty" has the Ember.js component value:');
    console.log(this.exampleProperty);
    Ember.$('body').click(this, this.exampleMethod).click();
    console.log('end didInsertElement() ************************************************************');
  },
  exampleMethod(event) {
    console.log('start exampleMethod() ************************************************************');
    console.log('- "this" is the DOM element that has triggered the event:');
    console.log(Ember.$(this));
    // console.log(this.$()); This doesn't work
    console.log('- "this.exampleProperty" is undefined:');
    console.log(this.exampleProperty);
    console.log('- To access the component\'s "this.exampleProperty" the event data must be used:');
    const exampleComponent = event.data;
    console.log(exampleComponent.exampleProperty);
    console.log('end exampleMethod() ************************************************************');
  },
});
import Ember from 'ember';

export default Ember.Component.extend({

  exampleProperty: 'example value',

  didInsertElement() {    
    this._super(...arguments);
    // create a new function with 'this' as bound argument
    this.exampleMethod = this.exampleMethod.bind(this);
    // bind exampleMethod() function to event without arguments
    Ember.$('body').click(this, this.exampleMethod).click();
  },
  willDestroyElement() {
    this._super(...arguments);
    // unbind exampleMethod() function from event successfully without arguments
    Ember.$('body').off('click', this.exampleMethod);
  },
  exampleMethod() {
    // inside exampleMethod() 'this' is the Ember.js component 
    // as bound before, not the DOM element that has triggered the event
    console.log('Ember.js property: ", this.get('exampleProperty')); 
  },
});
// bind() creates a new function which here is anonymous
Ember.$('body').click(this, this.exampleMethod.bind(this));
// this.exampleMethod() is not the former anonymous function
Ember.$('body').off('click', this.exampleMethod);
// here things are worse as a new anonymous function is created
Ember.$('body').off('click', this.exampleMethod.bind(this));
为了以后能够引用新绑定函数,必须将其命名为:

// create new bound function and store it in 'this.exampleMethod'
this.exampleMethod = this.exampleMethod.bind(this);
// bound function this.exampleMethod() referenced
Ember.$('body').click(this, this.exampleMethod);
// same bound function this.exampleMethod() referenced again
Ember.$('body').off('click', this.exampleMethod);

很好!实际上,只需要
.bind(this)
函数,不再需要
this
上下文。然后:
Ember.$('body')。单击(this.exampleMethod.bind(this))。单击()漂亮干净的解决方案!我仍然坚持使用
bind()
函数解决方案,但此处显示的方法确实不允许稍后解除事件绑定,如图所示。所以我想记录一个。谢谢,它很有效。为了使其更简单,不需要使用
事件参数,因此,依次使用
didInsertElement()
Ember.$('body')。单击(this.\u exampleMethodHandler)。单击()
,并删除方法声明上的
事件
参数:
exampleMethod()
。不过,我会坚持保罗·毕晓普的解决方案,因为它更简单。我正在使用
willDestroyElement()
事件,但没有方法处理程序,直接解除方法事件的绑定:
Ember.$('body').off('click',this.exampleMethod)谢谢。我更新了我的答案。我引入了缓存来进行适当的分解,您可以在余烬中看到。$('body').off('click',this.exampleMethod);这不会破坏事件处理程序。当我们使用bind函数时,我们需要注意它的陷阱。