我有一个鼠标事件类。我正在使用dojo b / c我喜欢它的OO方法
dojo.declare("MouseObject", null, {
constructor: function(){},
onclick : function(){...},
_onClick : function(){...}
});
_onClick()
侦听窗口生成的鼠标按下/释放事件,并确定是否发生了点击。如果有,则调用onClick()
。 onClick()
执行所有可能点击通用的功能,因此每次用户点击时都需要调用它。
有时用户可能希望扩展onClick()
的功能无论如何都要合并原始功能而不复制粘贴它?我能想到的两种方式,无论我喜欢哪种方式,都是
dojo.declare("MouseObjectChild", [MouseObject], {
constructor: function(){},
onclick : function(){this.inherited(arguments);...}
});
其缺点是我必须继续创建我不需要的新类,并且两个添加中间函数
dojo.declare("MouseObject", null, {
constructor: function(){},
onclick : function(){this._onClick()...}, //child onClick
_onClick : function(){...}, //parent onClick
__onClick : function(){...} //listener
});
但这看起来不是很好的代码
获得赏金,我想就如何最好地解决程序 - 用户交互提出专家建议。如果程序提供了一个关键功能,例如在画布上绘制一个圆圈,那么用户如何最好地与之交互。如果用户想在圆圈后面画一个三角形怎么办?圆圈前方的一个正方形?然后程序必须提供这样的前后方法:
beforeDraw();
draw();
afterDraw();
这被认为是好的设计吗?我应该把函数指针放在一个数组中并按顺序调用它们吗?
答案 0 :(得分:1)
如果有人只想在调用onclick()时运行一些代码,他就可以连接到它。请注意,您还可以连接到函数调用,而不仅仅是使用dojo.connect()。
的事件dojo.connect(obj, 'onclick', function(){
// Some extra code that runs when obj.onclick() is called
});
如果他想创建一个新类并扩展调用this.inherited(arguments);
的功能,那么这是最好的方法。
答案 1 :(得分:1)
为什么不创建自己的简单事件模型?
// store our callbacks
var hooks = {};
// add a callback
var hook = function(name,fn){
if(typeof hooks[name] === 'undefined'){
hooks[name] = [];
}
hooks[name].push(fn);
return true;
};
// remove a callback
var unhook = function(name,fn){
if(typeof hooks[name] === 'undefined'){ return false }
var i, u = hooks[name].length;
for(i=0;i<u;i++){
if(hooks[name][i] === fn){
hooks[name].splice(i,1);
return true;
}
}
};
// trigger a callback
var callHook = function(name, data){
if(typeof hooks[name] === 'undefined'){ return false }
var i, u = hooks[name].length;
for(i=0;i<u;i++){
hooks[name][i](data);
}
};
然后稍后(示例传递上下文):
hook('beforeDraw',function(ctx){
console.log('I am called prior to drawing');
});
hook('afterDraw',function(ctx){
console.log('I am called after drawing');
});
var drawCircle = function(){
callHook('beforeDraw', ctx);
// drawing code here
callHook('afterDraw', ctx);
};
或者,如果您想将范围传递给回调,则可以更改callHook
方法以接受范围参数,然后使用call
或apply
并传入{{1或其他一些对象:
this
取决于&amp;在定义事件模型函数的地方,您可以根据您希望分配,更改和触发这些回调的方式,将功能范围限定为对象的特定实例,对象的每个实例,全局等等。
答案 2 :(得分:1)
您有多种选择 1. Promise模式越来越受欢迎(虽然有竞争规格):http://wiki.commonjs.org/wiki/Promises/B。 jQuery有一个接近B的实现,并且有很好的文档记录。它具有最多的选择,它很强大,但最初并不容易包围。
例如:
var MYAPP = {
onClick: function () {
//do something...
}
};
dojo.declare("MouseObject", null, {
constructor: function(){},
onclick : function(){...},
_onClick : function(){
return MYAPP.onClick.apply(this, arguments);
}
});
由于我的班级每次都会调用MYAPP(是的,这是一个范围内的收费),我可以操纵悬挂在MYAPP上的功能,任何使用它的人都会受益。
MYAPP.after("onClick", function () {...}); //lots of ways to write .after, just google some AOP js or use a library
另一方:
var MYAPP = {
onClick: function () {
//do something...
}
};
dojo.declare("MouseObject", null, {
constructor: function(){},
onclick : function(){...},
_onClick : MYAPP.onClick
});
现在我无法更改MYAPP并查看MouseObject或其实例中的更改,因为该函数已通过引用传递给MouseObject。我只能通过AOP(或通过更改类中的原型来更改所有未来实例)来更改实例。
类似的东西:
var m = new MouseObject();
m.after("onClick", function () {...}); //you need to add .after to your class or use an apply pattern from library code
这取决于您如何使用它:某些实例,所有未来实例(直到关闭)或所有内容。
答案 3 :(得分:1)
正如“我应该将函数放在自己的数组中并按顺序调用它们”和“构建自己的事件系统”的想法所建议的那样,您可能希望查看捆绑的dojox.lang.aspect库在扩展标准库中。它基本上应该是“dojo.connect”解决方案的更高级版本。
dojo.require('dojox.lang.aspect');
var aop = dojox.lang.aspect;
function log(msg){ return function(){
console.log(msg);
};}
var obj = {
draw : log('draw circle');
};
obj.foo();
//prints
// draw circle
aop.advise(obj, 'draw', [
{before: log('draw triangle')},
{after: log('draw a square')},
{after: log('done!')}
]);
obj.foo();
//prints
// draw a triangle
// draw a circle
// draw a square
// done!
答案 4 :(得分:0)
__ fn变得更加混乱和混乱。那个,我的朋友,是通往地狱的道路。
使用Magic Pushbutton方法是一种症状。 您应该考虑使用许多OO js库转移到基于实际继承的类模型。然后你就可以调用$ base.fn()或$ super.fn()
答案 5 :(得分:0)
如果我理解您的问题,那么您希望修改特定情况的功能。如果是这种情况,并且您不需要任何开销,那么我将依赖于实例化时的重写方法。
覆盖模型
你的班级:
dojo.declare("some.path.DrawingThing", [dijit._Widget], {
draw: function () {
this.inherited(arguments); // Call super class methods
// override this method to do specialized things that're specific
// to an instance.
}
});
客户实例化:
var drawer = new some.path.DrawingThing({
draw: function () {
beforeDraw();
// Access the pre-existing functionality in a somewhat dirty way.
this.constructor.prototype.draw.apply(this, arguments);
afterDraw();
}
});
如果您遵循此模型,则代码较少,但不是那么干净。另一种选择是编写一个真正的API,见下文。
活动模型
如果你想要一个真正的API,那么我会提供一些事件:
// Dojo 1.6 style declaration.
dojo.declare("some.path.DrawingThing", [dijit._Widget], {
onBeforeDraw: function(){
// Hook into this method to do something before draw
},
onDraw: function(){
// Hook into this method to do something after draw
},
draw: function () {
// This method is actually called when the draw even fires
this.onBeforeDraw();
this.inherited(arguments); // Call super class methods
this.onDraw();
}
});