- windows XP |
- windows vista |
- windows 2000 |
- windows 2003 |
- windows 2008 |
- linux |
- unix |
- mac
- access |
- mysql |
- sql server |
- oracle |
- DB2
- word |
- excel |
- powerpoint |
- wps |
|
图 1. 后退、前进和刷新的历史记录按钮显示在左侧,不可用状态显示在右侧 |
可重用的设计
JavaScript 使用非常宽松的方法创建对象和类,但仍然能够建立可重用的代码。首先列出历史堆栈需要的功能,然后用 JavaScript 建立堆栈模型。在把历史堆栈集成到相册应用程序之前,首先要建立一个简单的页面来测试其功能。这样做有两方面的好处:测试页有助于将精力集中到开发和测试类的核心功能上,建立单独的测试页可以避免混淆历史堆栈和相册的功能,从而确保可重用性。
用 cookie 缓冲
我们需要应用程序的历史记录在整个浏览器会话中都存在。只要用户仍在查看相册页面,历史堆栈对象就会一直存在。每当发生更改的时候,这个类就会将整个历史记录复制到浏览器 cookie 中。如果用户在同一个浏览器会话中离开该页之后又返回,那么将返回他离开该应用程序时所在的同一个位置。
编写类
我们来看看历史堆栈中需要存储的数据或属性。前面已经讨论了堆栈(数组)和指针。stack_limit 属性可以防止因为数据过多而造成的 cookie 溢出(参见清单 1)。在实践中,我们希望在删除最老的记录之前能够存储 40-50 个事件。出于测试的目的,我们将该值设置为 15。
清单 1. 历史堆栈的构造,包括类的属性
| function HistoryStack () { this.stack = new Array(); this.current = -1; this.stack_limit = 15; } |
| HistoryStack.prototype.addResource = function(resource) { if (this.stack.length > 0) { this.stack = this.stack.slice(0, this.current + 1); } this.stack.push(resource); while (this.stack.length > this.stack_limit) { this.stack.shift(); } this.current = this.stack.length - 1; this.save(); }; |
| HistoryStack.prototype.addResource = function(resource) HistoryStack.prototype.getCurrent = function () { return this.stack[this.current]; }; HistoryStack.prototype.hasPrev = function() { return (this.current > 0); }; HistoryStack.prototype.hasNext = function() { return (this.current < this.stack.length - 1 && this.current > -1); }; |
| HistoryStack.prototype.go = function(increment) { // Go back... if (increment < 0) { this.current = Math.max(0, this.current + increment); // Go forward... } else if (increment > 0) { this.current = Math.min(this.stack.length - 1,this.current + increment); // Reload... } else { location.reload(); } this.save(); }; |
| HistoryStack.prototype.setCookie = function(name, value) { var cookie_str = name + "=" + escape(value); document.cookie = cookie_str; }; HistoryStack.prototype.getCookie = function(name) { if (!name) return ''; var raw_cookies, tmp, i; var cookies = new Array(); raw_cookies = document.cookie.split('; '); for (i=0; i < raw_cookies.length; i++) { tmp = raw_cookies[i].split('='); cookies[tmp[0]] = unescape(tmp[1]); } if (cookies[name] != null) { return cookies[name]; } else { return ''; } }; |
| HistoryStack.prototype.save = function() { this.setCookie('CHStack', this.stack.toString()); this.setCookie('CHCurrent', this.current); }; HistoryStack.prototype.load = function() { var tmp_stack = this.getCookie('CHStack'); if (tmp_stack != '') { this.stack = tmp_stack.split(','); } var tmp_current = parseInt(this.getCookie('CHCurrent')); if (tmp_current >= -1) { this.current = tmp_current; } }; |