添加具有特定回调的通用事件侦听器
Adding generic event listener with specific callback
在 Aurelia 视图模型组件中,我有以下 JQuery 代码可用于捕获 Ctrl+S 或 Ctrl+Enter 当模态可见时调用保存函数:
$(window).bind('keydown', function(event) {
if (event.ctrlKey || event.metaKey) { // Ctrl + ___
if ((event.which == 83) || (event.which == 115) || (event.which == 10) || (event.which == 13)) { // Ctrl+Enter or Ctrl+S
// Save button
event.preventDefault();
if ($(self.edit_calendar).is(':visible')) {
self.saveCalendar();
}
}
}
});
但是,我预见到将向 40 多个视图模型添加类似的功能,这看起来不是很枯燥,并且向我的每个视图模型添加了一些丑陋的代码。我想在单例 class 中创建一个通用的 addEventListener 函数,以便从我的每个视图中轻松调用。这是我的想法:
addListenerSave(visible, callback) {
// Add an event listener to redirect keyboard shortcuts to specific actions
console.log("addListenerSave()");
$(window).bind('keydown', function(event) {
if (event.ctrlKey || event.metaKey) { // Ctrl + ___
if ((event.which == 83) || (event.which == 115) || (event.which == 10) || (event.which == 13)) { // Ctrl+Enter or Ctrl+S
// Save button
event.preventDefault();
if ($(visible).is(':visible')) {
console.log("Keyboard shortcut: Save");
callback();
}
}
}
});
}
然后,在我的各个组件中,我应该只需要以下实例化代码(在attached()
组件生命周期中):
this.config.addListenerSave(this.edit_calendar, this.saveCalendar);
但是,这不起作用。 saveCalendar()
被调用但可能来自另一个 scope/context,所以我在 saveCalendar
中得到一个错误,它说:
"Cannot read property 'selectedId' of undefined".
这是指 saveCalendar()
代码 if (this.selectedId)...
。我做错了什么?
最后,当我的 Aurelia 组件分离时,我是否也应该删除这个事件侦听器?怎么样?
我的另一个想法是使用 Aurelia 的 eventAggregator
创建一个始终监听 Ctrl+S[= 的全局事件监听器42=]或者Ctrl+回车然后在各个组件中发布可以订阅的消息
我成功实现了添加全局事件侦听器的替代解决方案,该侦听器使用 Aurelia 的 EventAggregator 共享 Ctrl+S/Ctrl+Enter。最初的问题仍然存在,但也许这不是最好的方法。这是我的解决方案:
config.js(全局单例class)
@inject(EventAggregator)
export class Config {
constructor(eventAggregator) {
var self = this;
this.eventAggregator = eventAggregator;
// listen for Ctrl+S or Ctrl+Enter and publish event
window.addEventListener("keydown", function(event) {
if (event.ctrlKey || event.metaKey) { // Ctrl + ___
if ((event.keyCode == 83) || (event.keyCode == 115) || (event.keyCode == 10) || (event.keyCode == 13)) { // Ctrl+Enter or Ctrl+S
// Save button
console.log("Publishing ewKeyboardShortcutSave...");
event.preventDefault();
self.eventAggregator.publish('ewKeyboardShortcutSave', true);
}
}
});
}
}
然后,在我的组件视图模型中 calendar.js:
@inject(EventAggregator)
export class Calendar {
constructor(eventAggregator) {
this.eventAggregator = eventAggregator;
}
attached() {
var self = this;
// Ctrl+Enter is save
this.eventAggregator.subscribe('ewKeyboardShortcutSave', response => {
console.log("I heard ewKeyboardShortcutSave: " + response);
if ($(self.edit_calendar).is(':visible')) {
self.saveCalendar();
}
});
}
}
非常有效,现在我可以自由添加更多组件事件侦听器,甚至可以扩展功能为 Ctrl+F(用于查找)等添加全局侦听器
要回答您最初的问题,您的方向是正确的 - 但由于 this
在 JavaScript 中的语义,您需要绑定您的函数。 (如果您从 C# 的角度来看,认为 JavaScript 中的所有函数本质上都是扩展方法可能会有所帮助;因此,传递函数可能非常强大。)由于新的ES6 class 语法。
这应该可以缓解您的问题:
this.config.addListenerSave(this.edit_calendar, this.saveCalendar.bind(this));
就是说,您使用 Aurelia 的事件聚合器的解决方案更适合您的用例并且更具可扩展性。我想我会 post 这个答案来解决原来的问题,这只是一个功能范围的问题。
在 Aurelia 视图模型组件中,我有以下 JQuery 代码可用于捕获 Ctrl+S 或 Ctrl+Enter 当模态可见时调用保存函数:
$(window).bind('keydown', function(event) {
if (event.ctrlKey || event.metaKey) { // Ctrl + ___
if ((event.which == 83) || (event.which == 115) || (event.which == 10) || (event.which == 13)) { // Ctrl+Enter or Ctrl+S
// Save button
event.preventDefault();
if ($(self.edit_calendar).is(':visible')) {
self.saveCalendar();
}
}
}
});
但是,我预见到将向 40 多个视图模型添加类似的功能,这看起来不是很枯燥,并且向我的每个视图模型添加了一些丑陋的代码。我想在单例 class 中创建一个通用的 addEventListener 函数,以便从我的每个视图中轻松调用。这是我的想法:
addListenerSave(visible, callback) {
// Add an event listener to redirect keyboard shortcuts to specific actions
console.log("addListenerSave()");
$(window).bind('keydown', function(event) {
if (event.ctrlKey || event.metaKey) { // Ctrl + ___
if ((event.which == 83) || (event.which == 115) || (event.which == 10) || (event.which == 13)) { // Ctrl+Enter or Ctrl+S
// Save button
event.preventDefault();
if ($(visible).is(':visible')) {
console.log("Keyboard shortcut: Save");
callback();
}
}
}
});
}
然后,在我的各个组件中,我应该只需要以下实例化代码(在attached()
组件生命周期中):
this.config.addListenerSave(this.edit_calendar, this.saveCalendar);
但是,这不起作用。 saveCalendar()
被调用但可能来自另一个 scope/context,所以我在 saveCalendar
中得到一个错误,它说:
"Cannot read property 'selectedId' of undefined".
这是指 saveCalendar()
代码 if (this.selectedId)...
。我做错了什么?
最后,当我的 Aurelia 组件分离时,我是否也应该删除这个事件侦听器?怎么样?
我的另一个想法是使用 Aurelia 的 eventAggregator
创建一个始终监听 Ctrl+S[= 的全局事件监听器42=]或者Ctrl+回车然后在各个组件中发布可以订阅的消息
我成功实现了添加全局事件侦听器的替代解决方案,该侦听器使用 Aurelia 的 EventAggregator 共享 Ctrl+S/Ctrl+Enter。最初的问题仍然存在,但也许这不是最好的方法。这是我的解决方案:
config.js(全局单例class)
@inject(EventAggregator)
export class Config {
constructor(eventAggregator) {
var self = this;
this.eventAggregator = eventAggregator;
// listen for Ctrl+S or Ctrl+Enter and publish event
window.addEventListener("keydown", function(event) {
if (event.ctrlKey || event.metaKey) { // Ctrl + ___
if ((event.keyCode == 83) || (event.keyCode == 115) || (event.keyCode == 10) || (event.keyCode == 13)) { // Ctrl+Enter or Ctrl+S
// Save button
console.log("Publishing ewKeyboardShortcutSave...");
event.preventDefault();
self.eventAggregator.publish('ewKeyboardShortcutSave', true);
}
}
});
}
}
然后,在我的组件视图模型中 calendar.js:
@inject(EventAggregator)
export class Calendar {
constructor(eventAggregator) {
this.eventAggregator = eventAggregator;
}
attached() {
var self = this;
// Ctrl+Enter is save
this.eventAggregator.subscribe('ewKeyboardShortcutSave', response => {
console.log("I heard ewKeyboardShortcutSave: " + response);
if ($(self.edit_calendar).is(':visible')) {
self.saveCalendar();
}
});
}
}
非常有效,现在我可以自由添加更多组件事件侦听器,甚至可以扩展功能为 Ctrl+F(用于查找)等添加全局侦听器
要回答您最初的问题,您的方向是正确的 - 但由于 this
在 JavaScript 中的语义,您需要绑定您的函数。 (如果您从 C# 的角度来看,认为 JavaScript 中的所有函数本质上都是扩展方法可能会有所帮助;因此,传递函数可能非常强大。)由于新的ES6 class 语法。
这应该可以缓解您的问题:
this.config.addListenerSave(this.edit_calendar, this.saveCalendar.bind(this));
就是说,您使用 Aurelia 的事件聚合器的解决方案更适合您的用例并且更具可扩展性。我想我会 post 这个答案来解决原来的问题,这只是一个功能范围的问题。