假设我有一个对象Foo,实例化为bar = new Foo()
function Foo(){}; Foo.prototype.name = "Herring"; Foo.prototype.doSomething = function(e) { alert(this.name); }; bar = new Foo();
然后使用数据单击附加事件
<a data-role="button" data-click="bar.doSomething">Click Me</a>
bar的对象上下文被替换(不知道为什么,因为我们有方便的元素容器.)所以this.name是未定义的.
我试过旧的var self = this;在对象构造函数中,但它不起作用,有谁知道解决这个问题的最佳方法是什么?
更新:Hacky解决方法
因为我真的不想失去将模块包装为类的好处,所以我创建了事件调用函数包装器,然后调用适当对象上的方法.
<a data-role="button" data-click="doSomething">Click Me</a>
function doSomething(e){ bar.doSomething(e) };
现在,这实现了预期的结果,但它非常可怕,从标记调用的每个事件都必须具有类似上面的代理功能.所以想象一下你有300个事件的场景……你会立刻明白为什么这很糟糕.
如果没有其他解决方案,我非常希望有.我将这个解决方法作为答案发布,但就我而言,它远非理想.
脚注
我会完全诚实,这似乎是剑道的主要架构缺陷,因为这种从标记调用事件的方法是“剑道方式”.显然它无法修补,因为可能有一些代码已经将这个作为对html元素的引用处理.
能够覆盖它,或者能够通过可以传递调用的泛型处理程序(实质上是通用代理函数)来路由这些事件调用,是可以处理它的可能方法.它也可以是剑道上的简单可配置值.宾语.
理论解决方案
如果有效,我会发布后续内容,理论上可以在通用代理中抛出事件,并让它调用正确的范围函数.
假设我们使用event属性来调用代理,然后创建一个单独的属性来传达对象/方法调用.例如.
<a data-role="button" data-click="prox" data-prox="o.eventHandler">Click Me</a>
方法 – 使用eval
不是因为我是邪恶的,而是需要的.
// sitting in global namespace function prox(e){ var p = e.sender.element.data['prox']; // make sure our delegate is a function. if("function" == eval("typeof "+p)) { eval(p + "(e)"); } }
显然我想要一个更好的方法来做到这一点,但至少它是干的.
(我马上做一个非eval方法……)
放弃评估……
让我们使用窗口上下文来定位对象/方法.
function prox(e) { var p = e.sender.element.data['prox']; if(p.indexOf(".") == -1){ // global function : where *this* is window. // check you've got the function if not ditch it. if("function" == typeof window[p]) window[p](e); } else { // object/method (one level deep only.) var s = p.split("."); var o = s[0],m = s[1]; // check the object/method is a function before executing it. if("function" == typeof window[o][p]) window[o][p](e); } }
当然对于全局(窗口)范围的函数,这个元素可能更有用,但在这种情况下,你有一个选择,我会忽略
解决方法
// dynamic proxy for retaining object context on methods called by // data- attributes in Kendo. // // e.g. // // data-click="o.method" // // Would lose context with `o` - context would be set in the same // way as JQuery handlers,which is an inconvenience. // // Alternatively we use the prox method // // data-click="prox" // // We'd then set `data-prox` on the same element,to the // object.method pair. // // data-prox="o.method" // // This is read by prox,transformed into a method call,type // checked and executed if it's a valid method. // // A `data-prox` value in any form other than `object.method` will // be ignored,for example,`object.child.method` will fail. If // you're doing that sort of thing,feel free to hack it. // // There's a backup eval() to locate the object if window doesn't // own it. It should be possible to remove it under most // circumstances,it's here for compatability with // JSFiddle. (JSBin works without it.) function prox(e) { var p = this.element.data().prox; if(p.indexOf(".") > -1){ var s = p.split("."); if(s.length > 2) return; var o = s[0],m = s[1]; if("object" == typeof window[o]) { o = window[o]; } if("function" == typeof o[m]) o[m](e); // comment this out in production: l( "prox called " + s[0] + "::" + s[1] ); } } function l(s) { console.log(s); }
注意事项
如果在同一元素上有多个处理程序,则prox()是不合适的,例如,如果您有data-init,data-show等,则prox无法区分,并且将失败.
我可能会更新这个,特别是如果这对我来说是一个普遍的用例.