日期:2014-05-16  浏览次数:20393 次

Javascript 的函数式对象(八)DOM对象管理器

开发一个交互式的Web页面,用来显示信息或接受用户输入的对话框必不可少。

?

对话框的创建对应着页面上若干DOM节点的生成和插入,考虑到移除这些DOM节点的开销,

?

对话框的关闭只是将这些DOM节点在页面上设置为不显示。下面是一个js生成对话框的示例:

?

var Dialog = function(){
	
	this.element = document.createElement('div'); //创建对话框对应的DOM节点
	this.element.style.display = 'none'; // 指定div不显示
	this.element.style.position = 'absolute'; // 指定div的定位模式为绝对坐标模式
	this.element.style.border = 'gray solid'; //为Dialog加上灰色的边框
	this.element.className = 'dialog';
	// 在页面的body标签中插入刚创建的div标签
	document.getElementsByTagName('body')[0].appendChild(this.element);
};

Dialog.prototype = { //将无状态方法定义在Dialog对象的原型中
	show: function(x,y, contentHTML){
		//将传入的HTML字符串作为对话框内容,插入到新创建的div标签里
		this.element.innerHTML = contentHTML;
		this.element.style.left = x + 'px'; //指定div标签左侧的坐标
		this.element.style.top = y + 'px'; //指定div标签顶端的坐标
		this.element.style.display = 'block'; // 指定div显示
	},
	
	hide: function(){
		this.element.style.display = 'none'; // 指定div不显示
	},
	
	isVisible: function(){
		if(this.element.style.display == 'none'){
			return false;
		}else return true;
	}
};

var myDialog = new Dialog();
myDialog.show(200,100, '<h1>This is a dialog!</h1>');

?

上述代码虽然避免了移除对话框的DOM节点带来的开销,但是创建对话框DOM节点的过程依然会带来开销。

?

如果用户不断地重复“打开”+“关闭”对话框这一操作,大量DOM节点的产生,将迟滞浏览器响应速度,影响用户体验,

?

在DOM树结构较为复杂的页面上,尤为明显(早期的ExtJS上也曾出现过类似问题,在后来的版本中得以修正)。

?

下面这段代码将创建一个对话框对象管理器,托管页面上的所有对话框,其原理类似线程池:

?

当需要一个对话框显示内容的时候,首先遍历管理器,如果存在未被使用的对话框,这个对话框将用来显示内容。

?

如果当前所有的对话框都处在被使用的状态,则管理器负责新建一个对话框用来显示内容,并加入管理队列。

?

//定义对话框管理器,重用已创建的对话框。当管理器中的对话框不足时,将创建新的对话框
var DialogManager = (function(){

	var createdDialogs = []; //利用闭包创建的私有数组,
	
	return {
		display: function(x, y, contentHTML){
			//遍历管理器中的对话框,如果存在没有被使用的对话框,则用它显示内容,
			var hiddenIndex = 0;
			for(var i=0, len=createdDialogs.length; i<len; i++ ){
				
				if(!createdDialogs[i].isVisible()){
					createdDialogs[i].show(x, y, contentHTML);
					hiddenIndex = i;
					break;
				}
			}
			//如果所有对话框都处于显示的状态,那么创建一个新的对话框用于显示内容
			if(hiddenIndex == 0){
				var newDialog = new Dialog();
				newDialog.show(x, y, contentHTML);
				createdDialogs.push(newDialog);
				console.log('Dialog '+createdDialogs.length+' has been created!');
			}
		}
	}
})();

//调用管理器显示对话框内容
DialogManager.display(300,200,'<h1>This is a managed dialog!</h1>');
DialogManager.display(300,300,'<h1>This is another managed dialog!</h1>');

?

在涉及到DOM节点的创建和删除这类对性能有较大影响的操作时,对它们生命周期的托管是所有js框架的重要内容。

?

甚至大型js对象本身,如一些包含复杂数据类型的json对象,在频繁地创建和删除它们之前,都需要考虑性能上的影响。

?

?