widget.js中的构造函数代码this.handlers ={};需要去除。要在window.js的Window构造函数中把this.handlers ={};补上。
抽取widget抽象类:widget.js中的构造函数
function Widget(){
this.handlers ={};
},和window.js里的
function Window(){
this.handlers ={};
}这个this.handlers ={};可以去除也只能去除一个【或者两个都保存,保存的话引用的是window自己的handles】。而且应该要去除Widget里的代码
从面向对象的角度来说:对象的主要用途就是本身的属性,方法,其实方法也是xxxObj.xxfun(),也可以理解为一种属性。就是老师说的字典,从这节的代码来看,主要的作用是抽取handles这个obj放置在widget中,【PS:handles里面放的是各个类型的事件数组】。源代码中抽取了widget.js,然后再window.js中$.extends({},new widget.Widget(),{xxx:XXX})中就会把后面两个对象的属性和方法都挂载到了第一个对象{}上了。这时候,其实可以widget.js下的
function Widget(){
this.handlers ={};
}里的this.handlers ={};注释掉。因为function Window(){}构造函数中已经包含了这个定义了
function Window(){
XXXX..;
this.handlers = {};
}而main.js中实例化对象 var win = new w.Window();new的过程中自然就拥有了Window构造函数中的handles对象。实例win当然可以正确引用到handle。而且,这样引用的handler是自己实例中的handle,搜索树会比较短。效率比较高。如果去除window构造函数的this.handlers = {};这里引用的是window.js中
$.extends({},new widget.Widget(),{xxx:XXX})new new widget.Widget()产生的handles了。【ps:注意new widget.Widget()之后就产生了一个对象,包含了{key:val}这里就包含了handle:{}这样的key,val了】。
这时候(就是去除Window构造函数的this.handlers = {};不去除widget.js的语句)那么搜索的时候搜索的是Window构造函数原型链上的handler实例。所有的window对象都共享了这个prototype上的handle实例,所以会有bug。假设一个场景(index.html上初始化两个按钮,一个绑定了很多事件,一个不绑定)那么先点击绑定事件的按钮,弹出窗口(这个时候的窗口实例已经绑定了多个事件),然后关闭窗口,再点击不绑定事件的按钮,那么同样会弹出多个事件,因为共享了这个原型对象的handler实例。
简单的说。 Window.prototype= $.extend({},new widget.Widget(), {xxxx}这句代码执行后,如果 Window构造函数中去除this.handlers = {};,那么他找的是Window原型树的handle;如果去除了widget构造函数的this.handlers = {};那么找的是自己的handlers。
-----------------------------------------------------------------------------------------------------------------------
贴上主要代码
main.js,已经将jquery-ui下载到本地了。
/**
* Created by Administrator on 2015/7/21.
*/
require.config({
paths:{
jquery:'jquery-2.1.1',
jqueryUI: 'jquery-ui'
}
});
require(['jquery','window'],function($,w){
$(function(){
$("#btna").on('click',function(){
var win = new w.Window();
win.alert({
width:300,
height:150,
y:50,
content:'hello',
title:'title',
hasCloseBtn:true,
skinClassName:'window_skin_a',
textAlertBtn:'hello',
dragHandle:'.window_header'
}).on("alert",function(){
alert("first alert");
}).on('alert',function(){
alert('second alert');
}).on('alert',function(){
alert("third alsert");
}).on('close',function(){
alert("second close");
})
});
$("#btnb").on('click',function(){
var win = new w.Window();
win.alert({
width:300,
height:150,
y:50,
content:'hello',
title:'title',
hasCloseBtn:true,
skinClassName:'window_skin_a',
textAlertBtn:'hello',
dragHandle:'.window_header'
});
});
})
})widget.js
/**
* Created by Administrator on 15-7-25.
*/
define(function(){
function Widget(){
// this.handlers = {};
}
Widget.prototype = {
on:function(type ,handler){
if(typeof this.handlers[type]=='undefined'){
this.handlers[type] =[];
}
this.handlers[type].push(handler);
return this;
},
fire:function(type,data){
if(this.handlers[type] instanceof Array){
var handles= this.handlers[type];
for(var i= 0,len=this.handlers[type].length;i<len;i++){
handles[i](data);
}
}
}
}
return {
Widget:Widget//这里不能加(),不然就跑方法了。
}
});window.js
define(['widget','jquery','jqueryUI'],function(widget,$,$UI){
function Window(){
this.cfg={
width:500,
height:300,
content:'',
handler4AlertBtn:null,
handler4CloseBtn:null,
hasMask:true,
title:'system title',
text4AlertBtn:'sure',
skinClassName:'',
hasCloseBtn:false,
isDraggable:true,
dragHandle:null
};
this.handlers = {};
};
Window.prototype= $.extend({},new widget.Widget(), {
alert:function(cfg){
var CFG = $.extend(this.cfg,cfg);
var that = this;
var boundingBox = $('<div class="window_boundingBox">' +
'<div class="window_header">'+CFG.title+'</div>' +
'<div class="window_body">'+CFG.content+'</div>' +
'<div class="window_footer"><input type="button" class="window_alertBtn" value="'+CFG.text4AlertBtn+'"/></div>' +
'</div>');
var mask = null;
if(CFG.hasMask){
mask = $('<div class="window_mask"></div>');
mask.appendTo("body");
}
if(CFG.isDraggable){
if(CFG.dragHandle){
boundingBox.draggable({handle:CFG.dragHandle});
}else{
boundingBox.draggable();
}
}
boundingBox.appendTo("body");
if(CFG.skinClassName!==""){
boundingBox.addClass(CFG.skinClassName);
}
if(CFG.hasCloseBtn){
var closeBtn = $('<span class="window_closeBtn">X</span>');
boundingBox.find(".window_header").append(closeBtn);
closeBtn.on("click",function(){
// CFG.handler4CloseBtn&&CFG.handler4CloseBtn();
that.fire("close");
boundingBox.remove();
mask&& mask.remove();
});
}
if(CFG.handler4CloseBtn){
this.on('close',CFG.handler4AlertBtn);
}
if(CFG.handler4AlertBtn){
this.on('alert',CFG.handler4CloseBtn);
}
var btn = boundingBox.find(".window_footer .window_alertBtn");
btn.on("click",function(){
// CFG.handler4AlertBtn&&CFG.handler4AlertBtn();
that.fire("alert");
boundingBox.remove();
mask&& mask.remove();
});
boundingBox.css({
width:CFG.width+"px",
height:CFG.height+"px",
left:(CFG.x||(window.innerWidth-CFG.width)/2)+'px',
top:(CFG.y||(window.innerHeight-CFG.height)/2)+'px'
});
return this;
},
prompt:function(){
console.log("prompt");
},
confirm:function(){
console.log("confirm");
}
});
return {Window:Window};
})index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <link href="css/base.css" type="text/css" rel="stylesheet"/> <link href="css/window.css" type="text/css" rel="stylesheet"/> <script src="js/require.js" data-main="js/main.js"></script> </head> <body> <input type="button" value="alert" id="btna"/> <input type="button" value="alert" id="btnb"/> </body> </html>