我创建了一个名为SearchBox的类来处理搜索交互(延迟触发,搜索输入按键,防止搜索活动,搜索完成时同步结果,文本更改等)。
所有类方法都是原型方法,意味着可以通过this
访问。在下面的代码中,假设p
是类的原型。
p.registerListeners = function () {
$(this.element).on('keypress', this.searchKeyPressed);
};
p.unregisterListeners = function () {
$(this.element).off('keypress', this.searchKeyPressed);
};
这不起作用,因为当按键事件调用searchKeyPressed
处理程序时,它不会在this
的上下文中执行此操作。我能想出的唯一解决方案是只有现代浏览器支持的解决方案,即将回调绑定到this
,实际上创建了一个新函数。由于它创建了一个新函数,我必须将其缓存以便以后删除它,因为我必须将相同的引用传递给我传递给off
的{{1}}。
有没有比这更好的方法,或者这样可以吗?
on
我认为也许var boundKeyPressed;
p.registerListeners = function () {
boundKeyPressed = this.searchKeyPressed.bind(this);
$(this.element).on('keypress', boundKeyPressed);
};
p.unregisterListeners = function () {
$(this.element).off('keypress', boundKeyPressed);
};
会提供一种自动执行此事件绑定的方法,但似乎它会根据它的调用方式将jQuery.on
绑定到不同的事物上。例如,使用this
时,on('eventname',instance.func)
是" currentTarget" (不一定"目标"以冒泡的方式),而当使用this
时,on('eventname','selector',instance.func)
指的是与选择器匹配的元素。在任何一种情况下,this
都会运行,就好像它与func
无关。
答案 0 :(得分:3)
如果您为事件添加命名空间,则可以绑定事件并轻松地将它们全部解除绑定。
要绑定:
$(this.element).on('keypress.mynamespace', this.searchKeyPressed.bind(this));
取消绑定:
$(this.element).off('.mynamespace');
答案 1 :(得分:2)
首先,除非您希望自己的页面存在很长时间(或者您正在使用数百种内容来监听按键,这是一个非常大的架构问题),这不是即使手机有“钥匙”,也要成为一个存在问题的问题。
第二次,.bind
非常支持所有不到五年的浏览器,并且很容易被填充。
第三:你100%正确,为了能够稍后处理它而不得不缓存该功能,所以让我们做点什么
addEventListener
(和attachEvent
)有一个鲜为人知的技巧,因为它可以快速支持对象,并使用handleEvent
方法。
我不会把它用于所有东西,因为有时它真的不值得,但对于游戏制作,我用它来输入,有点像:
class Input {
constructor (events) {
this.events = events || [];
}
handleEvent (e) {
var input = this;
var method = e.type;
if (typeof input[method] === "function") {
input.dispatchEvent(method, e);
}
}
dispatchEvent (method, content) {
var input = this;
input[method](content);
}
listen (el, events) {
var input = this;
events = events || input.events;
events.forEach(event => el.addEventListener(event, input));
return this;
}
ignore (el, events) {
var input = this;
events = events || input.events;
events.forEach(event => el.removeEventListener(event, input));
return this;
}
}
class Keyboard extends Input {
constructor () {
super(["keydown", "keyup"]);
var keyboard = this;
keyboard.keys = new Set();
}
press (key) { this.keys.add(key); }
release (key) { this.keys.delete(key); }
isPressed (key) { return this.keys.has(key); }
keydown (e) {
var key = e.keyCode;
this.press(key);
}
keyup (e) {
var key = e.keyCode;
this.release(key);
}
}
我可以:
var gameplayEvents = ["keyup", "keydown"];
var keyboard = new Keyboard();
keyboard.listen(canvas, gameplayEvents);
// ongameover
keyboard.ignore(canvas, gameplayEvents);
如果你注意的话,那就是100%纯粹的JS。
没有jQuery,extJS等
而且,真的,严重的还不是更多的代码。
如果我只需要一个实例来处理mouseup和mousedown,我可以使它成为一个对象 - 文字;我真正需要的是一个带有handleEvent的对象,在handleEvent回调中成为this
。
只有一个例子需要担心。 如果我需要取消注册,我不会额外缓存任何内容。
jQuery(和其他人)实际上在内部使用它来优化他们通常被滥用的恶劣代码。
是的,也许我在使用ES6作弊......但是根本没有必要。
它比我以前做得更开心:
function Parent (args) { }
extend(Parent.prototype, { /*public-methods*/ });
function Child (args) {
Parent.call(this);
// construct
}
extend(
Child.prototype,
Parent.prototype,
{ /*public-override-methods*/ },
{ constructor: Child }
);
同样,有很多次绑定100%有效 现在有一个提议,对于ES7版本的bind,每次调用它时都会产生相同的值(如果它通过这种方式)。
还有一个额外的好处,即语法允许将各种可怕的东西链接在一起。
答案 2 :(得分:2)
您可以使用jQuery.proxy
function来保留上下文,而不是使用bind
,这会创建一个可以取消绑定的包装函数:
jQuery.proxy
有多种变体,但目前jQuery.proxy(function, context)
是你必须使用的:
p.registerListeners = function () {
$(this.element).on('keypress', $.proxy(this.searchKeyPressed, this));
};
p.unregisterListeners = function () {
$(this.element).off('keypress', $.proxy(this.searchKeyPressed, this));
};
答案 3 :(得分:0)
您可以使用闭包。
p.registerListeners = function() {
var me = this;
$(me.element).on('keypress', function() {
me.searchKeyPressed.apply(me, arguments);
});
};
使用apply传递参数。
答案 4 :(得分:0)
在构造函数中添加bind(this)
- 因此每次调用.bind
时都不会创建新函数。 bind
每次调用时都会创建新函数,因此如果您将其附加到$el.on("click", this.handler.bind(this))
,则无法将其与$el.off("click", this.handler.bind(this))
分离,因为处理程序不相同。 (this.handler.bind(this) !== this.handler.bind(this)
)如果您将该引用保存到该绑定函数(如构造函数this.handler = this.handler.bind(this)
中),那么您可以$el.on("click", this.handler)
和$el.off("click", this.handler)
,因为处理程序是相同的。
使用此方法,您实际上是覆盖该实例的该函数。它将不再像原型一样调用函数,而是在那个函数上运行。
function MyObject($el) {
this.testValue = "I am really this!";
this.$el = $el;
this.onClick = this.onClick.bind(this);
this.render();
}
MyObject.prototype.onClick = function(evt) {
console.log(this.testValue); // logs "I am really this!"
}
MyObject.prototype.render = function() {
var $a = $("<a>", {"text": "Click on me!"}).appendTo($el.empty());
$a.on("click", this.onClick);
}