控制器安装和卸载事件句柄非常容易。卸载事件句柄对于防止内存泄漏非常重要。
自动绑定
当一个新的控制器创建后,控制器原型方法那些是事件句柄。它会把使用控制器的事件委托功能把这些函数绑定控制器上。 当这个控制器销毁(或者对应的元素从页面上删除),控制器将自动卸载它的事件句柄。 例如:以下控制器的每个函数将自动绑定:
$.Controller("Crazy",{ // listens to all clicks on this element "click" : function(el, ev){}, // listens to all mouseovers on // li elements withing this controller "li mouseover" : function(el, ev){} // listens to the window being resized "{window} resize" : function(window, ev){} })
控制器通过函数名加空间,标准的DOM事件名,Jquery专用事件名(请查看$.event.special)。
一般而言,除了没有选择器和事件不在Jquery专用事件内,控制器都会知道自动绑定事件句柄。
如果遇到上面的情况,你就需要添加这个函数名到控制器的静态listensTo属性里。 例如:
$.Controller("MyShow",{ listensTo: ["show"] },{ show: function( el, ev ) { el.show(); } }) $('.show').my_show().trigger("show");
回调函数的传递参数
事件句柄绑定是控制器在元素上回调且把事件当成参数传递过来。this引用指的是控制器实例。例如:
$.Controller("Tabs",{ // li - the list element that was clicked // ev - the click event "li click" : function(li, ev){ this.tab(li).hide() }, tab : function(li){ return $(li.find("a").attr("href")) } })
模板匹配事件绑定
模板匹配事件句柄是控制器一个非常强大的特性。你可以把事件名,选择器,或者事件的根元素参数化。 模板匹配事件名称和选择器 常常,你想要创建一个配件行为配置。一个通俗的例子是菜单显示子菜单事件(例如:点击或者鼠标进入)。 以下控制器让你配置当一个菜单想显示子菜单时的事件。 以下创建2个按钮。
$.Controller("Menu",{ "li {showEvent}" : function(el){ el.children('ul').show() } }) $("#clickMe").menu({showEvent : "click"}); $("#touchMe").menu({showEvent : "mouseenter"});
$.Controller使用双括号来替换控制器中的options对应的值。这就意味着我们可以很容易实现一个默认的showEvent值来代替上面的作法, 而且创建菜单时,不需要再提供一个值了。例如:
$.Controller("Menu", { defaults : { showEvent : "click" } }, { "li {showEvent}" : function(el){ el.children('ul').show() } }); $("#clickMe").menu(); //defaults to using click
有时,我们可能想去配置我们的配件去使用不同的元素。下面是把菜单子菜单显示事件绑定到按钮上。
$.Controller("Menu",{ "{button} {showEvent}" : function(el){ el.children('ul').show() } }) $('#buttonMenu').menu({button: "button"});
模板匹配根元素
最后,控制器的事件句柄绑定到控制器元素外的对象上。 以下是监听窗口的点击事件:
$.Controller("HideOnClick",{ "{window} click" : function(){ this.element.hide() } })
如下是监听Todos的创建事件:
$.Controller("NewTodos",{ "{App.Models.Todo} created" : function(Todo, ev, newTodo){ this.element.append("newTodos.ejs", newTodo) } });
但是上面代码只能监听Todo Model的新建Todos的动作。我们也可以把它修改为可配置的:
$.Controller("Newbie",{ "{model} created" : function(Model, ev, newItem){ this.element.append(this.options.view, newItem) } }); $('#newItems').newbie({ model: App.Models.Todo, view: "newTodos.ejs" })
那么模板匹配到底是如何实现的呢?
当查找一个值去替换双括号,控制器首先想找在options中的项,如果没有查找到,再去Window对象中查找。这里不是使用eval去查找对象。 代替它的是使用了jQuery.String.getObject,详细请看语言助手(Language helpers)下的$.String.getObject,在这里不详细介绍。
预订OpenAjax信息和自定义绑定
使用jquery/controller/subscribe插件允许控制器监听OpenAjax.hub信息。 其实这个功能很像我们Java中的订阅模式,我们只需要预订对应事件,当事件发生时,会通知所有的订阅者。 例如:
steal('jquery/controller/subscribe').then(function(){ //这个控制器既是订阅者,又是发布者 $.Controller('subscribeTest',{ onDocument: false }, { "#subscribe1 click": function(el, ev){ ev.stopPropagation(); //点击按钮,向所有订阅者发布 this.publish("oaSubscribe1", {"params":"Hola Mundo"}); }, //订阅者收到发布的处理函数 "oaSubscribe1 subscribe": function(called, data){ alert("subscribeTest " + data.params + " : " + this.Class.shortName); } }); //这个控制器只是订阅者 $.Controller('subscribeTest1',{ onDocument: false }, { //订阅者2收到发布的处理函数 "oaSubscribe1 subscribe": function(called, data){ alert("subscribeTest1 " + data.params + " : " + this.Class.shortName); } }); var subscribeController = new subscribeTest($("#testSubscribe")[0]); var subscribeController1 = new subscribeTest1($("#subscribe2")); $("#off").bind("click",function(){ subscribeController.destroy(); subscribeController1.destroy(); }) });
手动绑定事件
控制器的原型bind和delegate方法都让监听其它元素的事件。这些事件句柄将在控制器实例销毁后去绑定。