关于奇矩互动奇矩互动招贤纳士奇矩互动优质虚拟主机Discuz!商业用户享有本站VIP服务LAMP环境配置手册(CentOS5.1)
发新话题
打印

PHP学心专题--第13期:PHP+Ajax Web开发基础篇

本主题由 Edwin 于 2008-4-6 11:41 设置高亮

PHP学心专题--第13期:PHP+Ajax Web开发基础篇

Ajax应用利用了一种中间的媒介(Ajax引擎)消除了用户和服务器交互间的等待。Ajax通过异步模式,提升了用户体验。优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用。因此Ajax已经成为Web开发中重要的技术应用。

Ajax基础概念
        Ajax的全称是 Asynchronous JavaScript and XML,Ajax的核心是JavaScript对象XmlHttpRequest。该对象在Internet Explorer 5中首次引入,它是一种支持异步请求的技术。简而言之,XmlHttpRequest使您可以使用JavaScript向服务器提出请求并处理响应,而不阻塞用户,下面我们将为初学者做详细的介绍。


如何学习AJAX

现在浏览器端以 JavaScript 为核心,基于各种 Web 标准(即:早已完成标准化的XHTML/CSS/DOM/XML/XSLT 和正在进行标准化的XMLHTTP)的技术正在加速整合,Ajax 就是这一系列技术的一个统称。

虽然网络上已经有大量的相关资源,但是为了打好基础,认真读上几本书还是很有必要的。

好在 Ajax 并不是什么全新的技术,它仅仅是传统技术的发展和增值,是对于这些基于 Web 标准的传统技术的重新包装,使其更加适合于企业应用,并且和服务器端结合地更加紧密。因此学习 Ajax,首先就要从深入学习这些传统的技术开始。

我由浅入深地列出一些我读过的书籍,提供给大家做参考:

1、XHTML 教程(XHTML)   作者:Chelsea Valentine, Chris Minnick   New Riders 原版,人民邮电出版社中文版
是的,今天你最应该学习的是 XHTML,而不是 HTML。HTML 4.x 已经是一个被废弃了的标准,今天的标准是 XHTML 1.0。XHTML 1.0 也不是 XHTML 最新的版本,但是它是目前唯一得到浏览器广泛支持和唯一实用的 XHTML 版本。

2、JavaScript 权威指南第四版(JavaScript: The Definitive Guide)   作者 avid Flanagan   O'Reilly 原版,中国电力出版社中文版
JavaScript 爱好者亲切地称之为“犀牛书”,因为 O'Reilly 以犀牛作为这本书的封面。这是目前 JavaScript 领域最深入和最权威的入门书。与其它 JavaScript 相关书籍的区别是这本书一半以上的篇幅着重于深入介绍 JavaScript 语言本身的基础知识,而不是象其它的书一样把基础知识和与 HTML 相结合做 Web 开发的内容(这些内容往往偏重于细节,使得其篇幅很容易就超出了 1000 页,例如《JavaScript Bible》)混杂在一起。对于刚刚开始学习 JavaScript 的初学者,这本书毫无疑问是最佳的入门书。

3、XML 高级编程(Professional XML)   Didier Martin等著   Wrox 原版,机械工业出版社中文版
这本书是关于 XML 开发技术非常详尽的著作。虽然因为作者众多(第一版 12 个人,第二版好像又多了几个),无法摆脱 Wrox 红皮书系列大杂烩的印记,但是这本书可以说是红皮书系列中少有的精品。
这本书可以作为 XML 技术参考书,虽然很厚,但是没有必要从头到尾全部读完。其中与 Ajax 相关的内容包括 XML DOM、XSLT 等等。  

4、网站重构(Designing with Web Standards)   作者:Jeffrey Zeldman   New Riders 原版,电子工业出版社中文版
这本书详细地介绍了如何摒弃远古时代(按照我的理解,3 年以前吧)不符合标准,专门针对某种浏览器(90%以上的情况下是 IE)做开发的恶习,真正采用符合标准的方式来做开发,最终走上向后兼容(注意:不是与浏览器以前不能完整支持 Web 标准的版本相兼容,而是与浏览器以后的版本相兼容)的平坦大路上来。这本书虽然不是 CSS 的专著,但是其中充分展示了使用 CSS 的一些高级技巧。尤其是最后一章展示了完全基于 CSS 做布局,摒弃使用 table 做布局的老方法的具体做法。
非常遗憾的是这本书的中文版翻译的非常烂,如果不对照原文,很容易误入歧途。读这本书有任何疑问的朋友都可以直接和我联系。   上面列出的是与 Ajax 涉及到的技术相关的书籍。我没有列出 CSS 的书,是因为我并没有专门读过一本 CSS 方面的专著。附件是网上流传很广的 CSS 2.0 中文手册,可以作为这方面的参考。
读了以上这些书,你已经在技术方面打下了极为坚实的基础,你还需要有一个经常的讨论场所,JavaEye 毫无疑问是你最值得来的地方。

下面我再列出几本与技术没有直接关系的书籍。

5、面向使用的软件设计(Software for Use)   作者 arry Contantine, Lucy Lockwood   ACM Press 原版,机械工业出版社中文版
大部分的软件都是给人使用的。我在 BEA User Group上的演讲中说到,Ajax 为什么会越来越流行,主要的原因就是它能比传统的基于 HTML FORM 的交互模式带给用户更好的交互体验,也就是 Ajax 可以实现更好的 Web 可用性(Web Usability,这是目前国外的一个专门的研究领域),这才是 Ajax 最大的价值。软件的可用性永远都是一个大的话题,《面向使用的软件设计》正是这方面最权威的专著。我们只要在做最终用户直接使用(有一个可视的界面)的软件开发,提高可用性就是我们需要孜孜不倦追求的目标。
6、软件创新之路(Inmates Are Running the Asylum)   作者:Alan Cooper   Sams Publishing 原版,电子工业出版社中文版   

7、About Face 2.0   作者:Alan Cooper   John Wiley & Sons 原版,中文版即将出版
上面两本书都是交互设计大师 Alan Cooper 的名著,相信很多朋友都知道 Alan Cooper 的大名,这两本书是交互设计爱好者必读的著作。

TOP

Ajax程序设计入门

一、使用Ajax的主要原因

1、通过适当的Ajax应用达到更好的用户体验;

2、把以前的一些服务器负担的工作转嫁到客户端,利于客户端闲置的处理能力来处理,减轻服务器和带宽的负担,从而达到节约ISP的空间及带宽租用成本的目的。

二、引用

Ajax这个概念的最早提出者Jesse James Garrett认为:Ajax是Asynchronous JavaScript and XML的缩写。Ajax并不是一门新的语言或技术,它实际上是几项技术按一定的方式组合在一在同共的协作中发挥各自的作用,它包括:

·使用XHTML和CSS标准化呈现;

·使用DOM实现动态显示和交互;

·使用XML和XSLT进行数据交换与处理;

·使用XMLHttpRequest进行异步数据读取;

·最后用JavaScript绑定和处理所有数据;

Ajax的工作原理相当于在用户和服务器之间加了—个中间层,使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器,像—些数据验证和数据处理等都交给Ajax引擎自己来做,只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。

三、概述

虽然Garrent列出了7条Ajax的构成技术,但个人认为,所谓的Ajax其核心只有JavaScript、XMLHTTPRequest和DOM,如果所用数据格式为XML的话,还可以再加上XML这一项(Ajax从服务器端返回的数据可以是XML格式,也可以是文本等其他格式)。

在旧的交互方式中,由用户触发一个HTTP请求到服务器,服务器对其进行处理后再返回一个新的HTHL页到客户端,每当服务器处理客户端提交的请求时,客户都只能空闲等待,并且哪怕只是一次很小的交互、只需从服务器端得到很简单的一个数据,都要返回一个完整的HTML页,而用户每次都要浪费时间和带宽去重新读取整个页面。

而使用Ajax后用户从感觉上几乎所有的操作都会很快响应没有页面重载(白屏)的等待。

1、XMLHTTPRequest

Ajax的一个最大的特点是无需刷新页面便可向服务器传输或读写数据(又称无刷新更新页面),这一特点主要得益于XMLHTTP组件XMLHTTPRequest对象。这样就可以向再发桌面应用程序只同服务器进行数据层面的交换,而不用每次都刷新界面也不用每次将数据处理的工作提交给服务器来做,这样即减轻了服务器的负担又加快了响应速度、缩短了用户等候时间。

最早应用XMLHTTP的是微软,IE(IE5以上)通过允许开发人员在Web页面内部使用XMLHTTP ActiveX组件扩展自身的功能,开发人员可以不用从当前的Web页面导航而直接传输数据到服务器上或者从服务器取数据。这个功能是很重要的,因为它帮助减少了无状态连接的痛苦,它还可以排除下载冗余HTML的需要,从而提高进程的速度。Mozilla(Mozilla1.0以上及NetScape7以上)做出的回应是创建它自己的继承XML代理类:XMLHttpRequest类。Konqueror (和Safari v1.2,同样也是基于KHTML的浏览器)也支持XMLHttpRequest对象,而Opera也将在其v7.6x+以后的版本中支持XMLHttpRequest对象。对于大多数情况,XMLHttpRequest对象和XMLHTTP组件很相似,方法和属性也类似,只是有一小部分属性不支持。

XMLHttpRequest的应用:

·XMLHttpRequest对象在JS中的应用

var xmlhttp = new XMLHttpRequest();

·微软的XMLHTTP组件在JS中的应用

var xmlhttp = new ActiveXObject(Microsoft.XMLHTTP);

var xmlhttp = new ActiveXObject(Msxml2.XMLHTTP);

XMLHttpRequest 对象方法

/**

* Cross-browser XMLHttpRequest instantiation.

*/

if (typeof XMLHttpRequest == ’undefined’) {

 XMLHttpRequest = function () {

var msxmls = [’MSXML3’, ’MSXML2’, ’Microsoft’]

for (var i=0; i < msxmls.length; i++) {

 try {

return new ActiveXObject(msxmls+’.XMLHTTP’)

 } catch (e) { }

}

throw new Error("No XML component installed!")

 }

}

function createXMLHttpRequest() {

 try {

// Attempt to create it "the Mozilla way"

if (window.XMLHttpRequest) {

 return new XMLHttpRequest();

}

// Guess not - now the IE way

if (window.ActiveXObject) {

 return new ActiveXObject(getXMLPrefix() + ".XmlHttp");

}

 }

 catch (ex) {}

 return false;

};

TOP

AJAX并不神秘:揭密各种AJAX控件和类库

Ajax控件和类库现在真的太多了,不知不觉中增加了Ajax的神秘性和复杂性,看到版内很多人为此费解和伤神,决定发此贴谈谈本人对Ajax的观点,希望能让大家对Ajax有一个本质的认识。

    观点一:Ajax和服务器端技术毫不相关

    严格的说,与传统web开发相比,Ajax是完完全全的客户端技术。由于很多控件封装了客户端和服务器端的通信过程,因此很多问题也因通信而起。事实上,不论何种Ajax技术,服务器端都是返回的一个纯文本流,再由客户端来处理这个文本。这段文本可以是xml格式,也可以是一个Html片段,也可以是一段JavaScript脚本,或者仅是一个字符串。服务器端仅仅是作为一个数据接口,客户端使用XMLHttpRequest对象来请求这个页面,服务器端在页面内写入结果文本,这个过程和普通的web开发没有任何区别。所不同的只是,客户端在异步获取结果后,不是直接显示在页面,而是由客户端的Javascript脚本处理后再显示在页面。至于各种控件所谓的能返回DataSet对象,Date对象,或者其他的数据类型,都是封装了这个处理过程的结果。

    观点二:DOM模型是Ajax最本质的技术

    之所以没有把XMLHttpRequest列为最本质的技术,因为本人觉得它实在是太简单了,它只是可以让浏览器在后台请求一个页面,并将其内容交给JavaScript处理。真正的核心应该是:DOM模型,即文档对象模型。在DOM模型里,Html标记都被认为是一个对象,例如:div对象,table对象等等。DOM模型就规定了这些对象所具有的属性、方法和事件。通过这些性质,可以对一个已经显示于浏览器的页面进行内容的修改,例如增加节点、修改节点位置,删除节点等等。而不仅仅是一个innerHTML属性这么简单,虽然这是一个很有用的属性。

   观点三:在使用Ajax控件前理解它们的实现

   使用Ajax控件的确可以提高效率,但如果你空中楼阁般使用控件,那就得不偿失了。从一个控件换到另外一个控件又会有一个漫长的学习曲线。所以应该从底层了解其,况且Ajax实在不是什么高深的技术。其实任何东西的最底层其实都是简单的,但如果封装了这些底层的东西,事情会变得复杂和难以理解。以Asp.net为例,它的定制特性可以使得只要在方法前加上[ajax method]类似这样的标志就可以称为一个异步方法,相信这使得Asp.net的Ajax开发显得更加“高效”或者是“神秘”,而更多的事情则被封装了。同样记住一条,任何对服务器端的请求仅仅是返回纯文本,我们不一定要依赖于封装好的处理过程,而完全可以自己来实现。

    观点四:学好JavaScript

    在大多数人看来,JavaScript总不是那么一种正规的语言,随便copy一段就碰巧能运行,学过c之类的人,一看也能看懂,而且在浏览器中常常有脚本错误提示,所以潜意识觉得总不能付之以大任。事实上,要学好Ajax,这就完全是一种错误的看法。javascript作为一种脚本语言,其语法的确不是很严格,但并不妨碍其完成诸多复杂的任务,没有JavaScript,就没有Ajax。所以本人强烈建议,学Ajax前,一定要好好研究一番JavaScript,一般来讲,如果能顺利看懂prototype框架的代码(如:prototype-1.3.1.js),你的JavaScript水平就基本过关了。同时对DOM模型也可以算有一个基本的了解。

    观点五:Ajax点缀:CSS

    用JavaScript控制CSS其实很简单,基本上每个DOM对象都有一个style对象,只要把css属性里的"-"去掉,并让随后的字母变为大写就可以作为属性使用了,例如:element.style.backgroundColor="#f00";在css是:选择符 {background-color:#f00}

TOP

AJAX入门之深入理解javascript中的函数

函数是进行模块化程序设计的基础,编写复杂的Ajax应用程序,必须对函数有更深入的了解。javascrīpt中的函数不同于其他的语言,每个函数都是作为一个对象被维护和运行的。通过函数对象的性质,可以很方便的将一个函数赋值给一个变量或者将函数作为参数传递。在继续讲述之前,先看一下函数的使用语法:

function func1(…){…}
var func2=function(…){…};
var func3=function func4(…){…};
var func5=new Function();

  这些都是声明函数的正确语法。它们和其他语言中常见的函数或之前介绍的函数定义方式有着很大的区别。那么在Javascrīpt中为什么能这么写?它所遵循的语法是什么呢?下面将介绍这些内容。

  认识函数对象(Function Object)

  可以用function关键字定义一个函数,并为每个函数指定一个函数名,通过函数名来进行调用。在Javascrīpt解释执行时,函数都是被维护为一个对象,这就是要介绍的函数对象(Function Object)。

  函数对象与其他用户所定义的对象有着本质的区别,这一类对象被称之为内部对象,例如日期对象(Date)、数组对象(Array)、字符串对象(String)都属于内部对象。这些内置对象的构造器是由Javascrīpt本身所定义的:通过执行new Array()这样的语句返回一个对象,Javascrīpt内部有一套机制来初始化返回的对象,而不是由用户来指定对象的构造方式。

  在Javascrīpt中,函数对象对应的类型是Function,正如数组对象对应的类型是Array,日期对象对应的类型是Date一样,可以通过new Function()来创建一个函数对象,也可以通过function关键字来创建一个对象。为了便于理解,我们比较函数对象的创建和数组对象的创建。先看数组对象:下面两行代码都是创建一个数组对象myArray:


var myArray=[];
//等价于
var myArray=new Array();
同样,下面的两段代码也都是创建一个函数myFunction:
function myFunction(a,b){
      return a+b;
}
//等价于
var myFunction=new Function("a","b","return a+b");

  通过和构造数组对象语句的比较,可以清楚的看到函数对象本质,前面介绍的函数声明是上述代码的第一种方式,而在解释器内部,当遇到这种语法时,就会自动构造一个Function对象,将函数作为一个内部的对象来存储和运行。从这里也可以看到,一个函数对象名称(函数变量)和一个普通变量名称具有同样的规范,都可以通过变量名来引用这个变量,但是函数变量名后面可以跟上括号和参数列表来进行函数调用。

  用new Function()的形式来创建一个函数不常见,因为一个函数体通常会有多条语句,如果将它们以一个字符串的形式作为参数传递,代码的可读性差。下面介绍一下其使用语法:


var funcName=new Function(p1,p2,...,pn,body);

  参数的类型都是字符串,p1到pn表示所创建函数的参数名称列表,body表示所创建函数的函数体语句,funcName就是所创建函数的名称。可以不指定任何参数创建一个空函数,不指定funcName创建一个无名函数,当然那样的函数没有任何意义。

  需要注意的是,p1到pn是参数名称的列表,即p1不仅能代表一个参数,它也可以是一个逗号隔开的参数列表,例如下面的定义是等价的:


new Function("a", "b", "c", "return a+b+c")
new Function("a, b, c", "return a+b+c")
new Function("a,b", "c", "return a+b+c")

  Javascrīpt引入Function类型并提供new Function()这样的语法是因为函数对象添加属性和方法就必须借助于Function这个类型。
函数的本质是一个内部对象,由Javascrīpt解释器决定其运行方式。通过上述代码创建的函数,在程序中可以使用函数名进行调用。本节开头列出的函数定义问题也得到了解释。注意可直接在函数声明后面加上括号就表示创建完成后立即进行函数调用,例如:


var i=function (a,b){
       return a+b;
}(1,2);
alert(i);

  这段代码会显示变量i的值等于3。i是表示返回的值,而不是创建的函数,因为括号“(”比等号“=”有更高的优先级。这样的代码可能并不常用,但当用户想在很长的代码段中进行模块化设计或者想避免命名冲突,这是一个不错的解决办法。

  需要注意的是,尽管下面两种创建函数的方法是等价的:


function funcName(){
       //函数体
}
//等价于
var funcName=function(){
       //函数体
}

  但前面一种方式创建的是有名函数,而后面是创建了一个无名函数,只是让一个变量指向了这个无名函数。在使用上仅有一点区别,就是:对于有名函数,它可以出现在调用之后再定义;而对于无名函数,它必须是在调用之前就已经定义。例如:


<scrīpt language="Javascrīpt" type="text/javascrīpt">
<!--
func();
var func=function(){
       alert(1)
}
//-->
</scrīpt>

  这段语句将产生func未定义的错误,而:


<scrīpt language="Javascrīpt" type="text/javascrīpt">
<!--
func();
function func(){
      alert(1)
}
//-->
</scrīpt>

  则能够正确执行,下面的语句也能正确执行:


<scrīpt language="Javascrīpt" type="text/javascrīpt">
<!--
func();
var someFunc=function func(){
      alert(1)
}
//-->
</scrīpt>

  由此可见,尽管Javascrīpt是一门解释型的语言,但它会在函数调用时,检查整个代码中是否存在相应的函数定义,这个函数名只有是通过function funcName()形式定义的才会有效,而不能是匿名函数。

  函数对象和其他内部对象的关系

  除了函数对象,还有很多内部对象,比如:Object、Array、Date、RegExp、Math、Error。这些名称实际上表示一个类型,可以通过new操作符返回一个对象。然而函数对象和其他对象不同,当用typeof得到一个函数对象的类型时,它仍然会返回字符串 “function”,而typeof一个数组对象或其他的对象时,它会返回字符串“object”。下面的代码示例了typeof不同类型的情况:



alert(typeof(Function)));
alert(typeof(new Function()));
alert(typeof(Array));
alert(typeof(Object));
alert(typeof(new Array()));
alert(typeof(new Date()));
alert(typeof(new Object()));

  运行这段代码可以发现:前面4条语句都会显示“function”,而后面3条语句则显示“object”,可见new一个function实际上是返回一个函数。这与其他的对象有很大的不同。其他的类型Array、Object等都会通过new操作符返回一个普通对象。尽管函数本身也是一个对象,但它与普通的对象还是有区别的,因为它同时也是对象构造器,也就是说,可以new一个函数来返回一个对象,这在前面已经介绍。所有typeof返回 “function”的对象都是函数对象。也称这样的对象为构造器(constructor),因而,所有的构造器都是对象,但不是所有的对象都是构造器。

  既然函数本身也是一个对象,它们的类型是function,联想到C++、Java等面向对象语言的类定义,可以猜测到Function类型的作用所在,那就是可以给函数对象本身定义一些方法和属性,借助于函数的prototype对象,可以很方便地修改和扩充Function类型的定义,例如下面扩展了函数类型Function,为其增加了method1方法,作用是弹出对话框显示 "function":


Function.prototype.method1=function(){
      alert("function");
}
function func1(a,b,c){
      return a+b+c;
}
func1.method1();
func1.method1.method1();

  注意最后一个语句:func1.method1.mehotd1(),它调用了method1这个函数对象的method1方法。虽然看上去有点容易混淆,但仔细观察一下语法还是很明确的:这是一个递归的定义。因为method1本身也是一个函数,所以它同样具有函数对象的属性和方法,所有对 Function类型的方法扩充都具有这样的递归性质。

  Function是所有函数对象的基础,而Object则是所有对象(包括函数对象)的基础。在Javascrīpt中,任何一个对象都是Object的实例,因此,可以修改Object这个类型来让所有的对象具有一些通用的属性和方法,修改Object类型是通过prototype来完成的:


Object.prototype.getType=function(){
       return typeof(this);
}
var array1=new Array();
function func1(a,b){
      return a+b;
}
alert(array1.getType());
alert(func1.getType());

  上面的代码为所有的对象添加了getType方法,作用是返回该对象的类型。两条alert语句分别会显示“object”和“function”。

  将函数作为参数传递

  在前面已经介绍了函数对象本质,每个函数都被表示为一个特殊的对象,可以方便的将其赋值给一个变量,再通过这个变量名进行函数调用。作为一个变量,它可以以参数的形式传递给另一个函数,这在前面介绍Javascrīpt事件处理机制中已经看到过这样的用法,例如下面的程序将func1作为参数传递给func2:


function func1(theFunc){
      theFunc();
}
function func2(){
      alert("ok");
}
func1(func2);

  在最后一条语句中,func2作为一个对象传递给了func1的形参theFunc,再由func1内部进行theFunc的调用。事实上,将函数作为参数传递,或者是将函数赋值给其他变量是所有事件机制的基础。

  例如,如果需要在页面载入时进行一些初始化工作,可以先定义一个init的初始化函数,再通过window.onload=init;语句将其绑定到页面载入完成的事件。这里的init就是一个函数对象,它可以加入window的onload事件列表。

  传递给函数的隐含参数:arguments

  当进行函数调用时,除了指定的参数外,还创建一个隐含的对象——arguments。arguments是一个类似数组但不是数组的对象,说它类似是因为它具有数组一样的访问性质,可以用arguments[index]这样的语法取值,拥有数组长度属性length。arguments对象存储的是实际传递给函数的参数,而不局限于函数声明所定义的参数列表,例如:


function func(a,b){
     alert(a);
     alert(b);
     for(var i=0;i<arguments.length;i++){
           alert(arguments);
     }
}
func(1,2,3);

  代码运行时会依次显示:1,2,1,2,3。因此,在定义函数的时候,即使不指定参数列表,仍然可以通过arguments引用到所获得的参数,这给编程带来了很大的灵活性。arguments对象的另一个属性是callee,它表示对函数对象本身的引用,这有利于实现无名函数的递归或者保证函数的封装性,例如使用递归来计算1到n的自然数之和:


var sum=function(n){
      if(1==n)return 1;
      else return n+sum(n-1);
}
alert(sum(100));

  其中函数内部包含了对sum自身的调用,然而对于Javascrīpt来说,函数名仅仅是一个变量名,在函数内部调用sum即相当于调用一个全局变量,不能很好的体现出是调用自身,所以使用arguments.callee属性会是一个较好的办法:


var sum=function(n){
      if(1==n)return 1;
      else return n+arguments.callee(n-1);
}
alert(sum(100));

  callee属性并不是arguments不同于数组对象的惟一特征,下面的代码说明了arguments不是由Array类型创建:


Array.prototype.p1=1;
alert(new Array().p1);
function func(){
       alert(arguments.p1);
}
func();

  运行代码可以发现,第一个alert语句显示为1,即表示数组对象拥有属性p1,而func调用则显示为“undefined”,即p1不是arguments的属性,由此可见,arguments并不是一个数组对象。


  函数的apply、call方法和length属性

  Javascrīpt为函数对象定义了两个方法:apply和call,它们的作用都是将函数绑定到另外一个对象上去运行,两者仅在定义参数的方式有所区别:



Function.prototype.apply(thisArg,argArray);
Function.prototype.call(thisArg[,arg1[,arg2…]]);

  从函数原型可以看到,第一个参数都被取名为thisArg,即所有函数内部的this指针都会被赋值为thisArg,这就实现了将函数作为另外一个对象的方法运行的目的。两个方法除了thisArg参数,都是为Function对象传递的参数。下面的代码说明了apply和call方法的工作方式:


//定义一个函数func1,具有属性p和方法A
function func1(){
      this.p="func1-";
      this.A=function(arg){
            alert(this.p+arg);
      }
}
//定义一个函数func2,具有属性p和方法B
function func2(){
      this.p="func2-";
      this.B=function(arg){
             alert(this.p+arg);
      }
}
var obj1=new func1();
var obj2=new func2();
obj1.A("byA");    //显示func1-byA
obj2.B("byB");    //显示func2-byB
obj1.A.apply(obj2,["byA"]); //显示func2-byA,其中[“byA”]是仅有一个元素的数组,下同
obj2.B.apply(obj1,["byB"]); //显示func1-byB
obj1.A.call(obj2,"byA");  //显示func2-byA
obj2.B.call(obj1,"byB");  //显示func1-byB

  可以看出,obj1的方法A被绑定到obj2运行后,整个函数A的运行环境就转移到了obj2,即this指针指向了obj2。同样obj2的函数B也可以绑定到obj1对象去运行。代码的最后4行显示了apply和call函数参数形式的区别。

  与arguments的length属性不同,函数对象还有一个属性length,它表示函数定义时所指定参数的个数,而非调用时实际传递的参数个数。例如下面的代码将显示2:


function sum(a,b){
      return a+b;
}
alert(sum.length);

  深入认识Javascrīpt中的this指针

  this指针是面向对象程序设计中的一项重要概念,它表示当前运行的对象。在实现对象的方法时,可以使用this指针来获得该对象自身的引用。

  和其他面向对象的语言不同,Javascrīpt中的this指针是一个动态的变量,一个方法内的this指针并不是始终指向定义该方法的对象的,在上一节讲函数的apply和call方法时已经有过这样的例子。为了方便理解,再来看下面的例子:


<scrīpt language="Javascrīpt" type="text/javascrīpt">
<!--
//创建两个空对象
var obj1=new Object();
var obj2=new Object();
//给两个对象都添加属性p,并分别等于1和2
obj1.p=1;
obj2.p=2;
//给obj1添加方法,用于显示p的值
obj1.getP=function(){
      alert(this.p); //表面上this指针指向的是obj1
}
//调用obj1的getP方法
obj1.getP();
//使obj2的getP方法等于obj1的getP方法
obj2.getP=obj1.getP;
//调用obj2的getP方法
obj2.getP();
//-->
</scrīpt>

  从代码的执行结果看,分别弹出对话框显示1和2。由此可见,getP函数仅定义了一次,在不同的场合运行,显示了不同的运行结果,这是有 this指针的变化所决定的。在obj1的getP方法中,this就指向了obj1对象,而在obj2的getP方法中,this就指向了obj2对象,并通过this指针引用到了两个对象都具有的属性p。

  由此可见,Javascrīpt中的this指针是一个动态变化的变量,它表明了当前运行该函数的对象。由this指针的性质,也可以更好的理解Javascrīpt中对象的本质:一个对象就是由一个或多个属性(方法)组成的集合。每个集合元素不是仅能属于一个集合,而是可以动态的属于多个集合。这样,一个方法(集合元素)由谁调用,this指针就指向谁。实际上,前面介绍的apply方法和call方法都是通过强制改变this指针的值来实现的,使this指针指向参数所指定的对象,从而达到将一个对象的方法作为另一个对象的方法运行。

  每个对象集合的元素(即属性或方法)也是一个独立的部分,全局函数和作为一个对象方法定义的函数之间没有任何区别,因为可以把全局函数和变量看作为window对象的方法和属性。也可以使用new操作符来操作一个对象的方法来返回一个对象,这样一个对象的方法也就可以定义为类的形式,其中的 this指针则会指向新创建的对象。在后面可以看到,这时对象名可以起到一个命名空间的作用,这是使用Javascrīpt进行面向对象程序设计的一个技巧。例如:


var namespace1=new Object();
namespace1.class1=function(){
     //初始化对象的代码
}
var obj1=new namespace1.class1();

  这里就可以把namespace1看成一个命名空间。

  由于对象属性(方法)的动态变化特性,一个对象的两个属性(方法)之间的互相引用,必须要通过this指针,而其他语言中,this关键字是可以省略的。如上面的例子中:


obj1.getP=function(){
      alert(this.p); //表面上this指针指向的是obj1
}

  这里的this关键字是不可省略的,即不能写成alert(p)的形式。这将使得getP函数去引用上下文环境中的p变量,而不是obj1的属性。

[ 本帖最后由 aming 于 2008-4-6 11:05 编辑 ]

TOP

xAjax的使用步骤

xajax是一个开源的、针对PHP的Ajax代码库。它的使用不算太难,从官方的说明来看,只需要七步就可以了:

首先,在php文件头包含xajax类

require_once("xajax.inc.php");
接下来,创建xajax对象

$xajax = new xajax();
注册你的函数。这个函数用于在服务器端处理相应的客户端请求,并返回指定内容。

$xajax->registerFunction("myFunction");
编写上述函数的代码。根据你要执行的功能

function myFunction($arg)
{
  // 在函数中使用从服务器或客户端得到的参数。
  $newContent = $arg;
   
  // 创建xajaxResponse对象。
  // 这个是用于被客户端调用并返回相应内容的函数中所必须定义的。
  $objResponse = new xajaxResponse();
   
  // 使用xajaxResponse对象中的方法,执行不同的操作。
  $objResponse->addAssign("SomeElementId","innerHTML", $newContent);
   
  // 向客户端返回内容。
  // 客户端的页面将在不刷新的情况下被重写。
  return $objResponse->getXML();
}
打开请求控制器,所以请求都将交由xajax系统来处理。

$xajax->processRequests();
在”head”标签中加入下列代码,用于在页面中生成必要的Javascript脚本。

<?php $xajax->printJavascript(); ?>
最后,在页面中有事件发生时,调用你在服务器端定义的函数来进行处理就可以了。这里是名为myFunction的函数。注意,调用时,函数前必须加xajax_前缀。

<div id="SomeElementId"></div>
<button onclick="xajax_myFunction(SomeArgument);">
这样,一个具有流行的Ajax效果的页面的做好了。怎么样,不复杂吧? 实际上,xajax还提供大量的方法,利用它们,你就可以很容易对页面进行操作了。详细文档请见下面的链接。

TOP

Ajax简单实例
        异步 Javascript 和 XML(Asynchronous Javascript and XML,Ajax)无疑是最流行的新 Web 技术。本文中我们将完全使用 PHP 和 Simple Ajax Toolkit (Sajax) 创建一个简单的相册作为在线 Web 应用程序。我们首先用标准的 PHP 开发方法编写简单的相册,然后再用 Sajax 将其变成活动的 Web 应用程序。

结合AJAX进行PHP开发之入门(1)异步 Javascript 和 XML(Asynchronous Javascript and XML,Ajax)无疑是最流行的新 Web 技术。本文中我们将完全使用 PHP 和 Simple Ajax Toolkit (Sajax) 创建一个简单的相册作为在线 Web 应用程序。我们首先用标准的 PHP 开发方法编写简单的相册,然后再用 Sajax 将其变成活动的 Web 应用程序。

  创建一个简单的相册

  本文将使用两种方法创建一个简单的相册:传统的 Web 应用程序和基于 Sajax 的应用程序。我们将用 PHP 编写一个相册,读取某一目录中的内容,显示缩略图组成的表格。如果用户单击一个缩略图,就会完全展开该图像。因为编写的是传统应用程序,所以每次单击都会是一个新的 HTTP 请求,而参数则作为 URL 的一部分传递。

  您将学习如何将 Sajax 库应用于相册,了解为何使用 Sajax 可以加快应用程序的开发。

  添加一个分页器表

  访问相册的用户需要某种快速查看照片的方法。因为很多大照片不容易在一页上显示,所以需要创建一个分页器 —— 每次显示少量缩略图的简单表格。还要编写导航,帮助用户在图像列表中来回移动。


  什么是 OpenAjax Alliance?

  2006 年 5 月 JavaOne Conference 开始前,29 家公司的代表在 Adobe Systems 的会议室里碰头,准备大体上确定 Ajax 的未来,这个小组就称为 OpenAjax Alliance。

  小组做了几项决定,其中最显著的就是给自己取了个名字:OpenAjax Alliance。它还决定不把自己组织成一个正式的标准团体,或者 Eclipse Foundation 那样的开放源码主导的组织,因此小组自身的形式暂时也是非正式的。小组同意大约每周召开一次电话会议。

  OpenAjax Alliance 主要关注三个方面:通过提供互操作性降低采用 Ajax 的风险,保证 Ajax 解决方案坚持走开放标准路线和使用开放源码技术,保持 Web 的开放性。小组的第一项任务就是寻求建立和保持 Ajax 工具间互操作性的方法。

  OpenAjax Alliance 包括 31 家技术公司,其中有 IBM?、Adobe Systems、Eclipse Foundation、Google、Laszlo Systems Inc.、Oracle、Red Hat Inc. 和 Zend Technologies Ltd.。

  首先要收集至少 20 幅 .jpg 图片,并将它们放到一个文件夹中。每个图片还要有一个保存在单独缩略图文件夹中的缩略图。虽然可使用 GD 软件包生成缩略图(请参阅 参考资料),但本文假设已经准备好了缩略图。也可使用本文提供的照片和缩略图(请参阅 下载)。

  为了完成本文的剩余部分,后面假设照片保存在 /images 子目录中,缩略图则放在 /images/thumbnails 中。可以在代码中做适当的修改。此外,我们还假定缩略图和对应的图像使用相同的名称。

  分页器应该传递两个参数:start 是按照字母顺序显示的第一幅照片的索引号,step 是显示的照片数。

  清单 1. 相册查看器

/*
* Find a list of images in /images and provide thumbnails
*/
function get_table ( $limit_start = 0, $limit_step = 5 ) {
 $images = get_image_list('images');

 // Generate navigation for Previous and Next buttons
 // Code given below

 $output .= '<table class="image_table">';
 $columns = 5;
 foreach ($images as $index => $image) {

  // Begin directory listing at item number $limit_start
  if ( $index < $limit_start ) continue;

  // End directory listing at item number $limit_end
  if ( $index >= $limit_start + $limit_step ) continue;

  // Begin column
  if ( $index - $limit_start % $columns == 0 ) {
   $output .= '<tr>';
  }

  // Generate link to blown up image (see below)
  $thumbnail = '<img src="thumbnails/' . $image . '" />';
  $output .= '<td>' . get_image_link($thumbnail, $index) . '</td>';

  // Close column
  if ( $index - $limit_start % $columns == $columns - 1 ) {
   $output .= '</tr>';
  }
 }

 $output .= '</table>';

 return $nav . $output;
}

  这个表很简单,它从索引号 $limit_start 开始遍历图片列表。然后放上每个图片的缩略图,每五张图片作为一行。达到 $limit_start + $limit_step 的时候循环结束。

  该表是目录列表的可视化表示,因此需要一个函数列出目录中的所有图像。清单 1 中的 get_file_list() 函数用索引数组返回 /images 目录中的所有图片列表。下面是一个示例实现。

  清单 2. get_file_list 实现

function get_image_list ( $image_dir ) {
 $d = dir($image_dir);
 $files = array();
 if ( !$d ) return null;

 while (false !== ($file = $d->read())) {
  // getimagesize returns true only on valid images
  if ( @getimagesize( $image_dir . '/' . $file ) ) {
   $files[] = $file;
  }
 }
 $d->close();
 return $files;
}

  注意:本文后面还要使用 get_file_list() 函数。有一点很重要,无论何时调用该函数,返回的数组都是不变的。因为提供的实现要进行目录搜索,必须保证目录中的指定文件不会改变,每次都要按字母顺序排序。

TOP

结合AJAX进行PHP开发之入门(2)

导航的实现

  虽然表格列出了目录中的一些图像,但用户还需要一种查看表格中未出现的图片的方法。要真正实现分页器的导行,则需要一套标准的链接:首页、上一页、下一页和尾页。

  清单 3. 分页器导航

// Append navigation
$output = '<h4>Showing items ' . $limit_start . '-' .
min($limit_start + $limit_step - 1, count($images)) .
' of ' . count($images) . '<br />';

$prev_start = max(0, $limit_start - $limit_step);
if ( $limit_start > 0 ) {
 $output .= get_table_link('<<', 0, $limit_step);
 $output .= ' | ' . get_table_link('Prev',
 $prev_start, $limit_step);
} else {
 $output .= '<< | Prev';
}

// Append next button
$next_start = min($limit_start + $limit_step, count($images));
if ( $limit_start + $limit_step < count($images) ) {
 $output .= ' | ' . get_table_link('Next',$next_start, $limit_step);
 $output .= ' | ' . get_table_link('>>',(count($images) - $limit_step), $limit_step);
} else {
 $output .= ' | Next | >>';
}

$output .= '</h4>';

  最后还要编写 get_image_link() 和 get_table_link() 函数,让用户将缩略图展开成完整的图像(参见清单 4)。注意,脚本 index.php(以及后面要创建的 expand.php)只在这两个函数中调用。这样就很容易改变链接的功能。事实上在下面与 Sajax 进行集成时,只有这两个函数需要修改。

  清单 4. get_image_link、get_table_link 实现

function get_table_link ( $title, $start, $step ) {
 $link = "index.php?start=$start&step=$step";
 return '<a href="' . $link . '">' . $title .'</a>';
}

function get_image_link ( $title, $index ) {
 $link = "expand.php?index=$index";
 return '<a href="' . $link . '">' . $title . '</a>';
}

  放大图片

  现在有了一个可用的分页器为用户提供一些缩略图。相册的第二项功能是允许用户单击缩略图来查看全图。get_image_link() 函数调用了 expand.php 脚本,我们现在就来编写它。该脚本传递用户希望展开的文件的索引,因此必须在此列出目录并获得适当的文件名。随后的操作就很简单了,只需创建病输出 image 标记即可。

  清单 5. get_image 函数

function get_image ( $index ) {
 $images = get_image_list ( 'images' );

 // Generate navigation

 $output .= '<img src="images/' . $images[$index] . '" />';
 return $output;
}

  接下来还要提供与分页器类似的导航机制。“上一张” 导航到编号为 $index-1 的图像,“下一张” 导航到编号为 $index+1 的图像,“返回” 则回到分页器。

  清单 6. get_image 导航

$output .= '<h4>Viewing image ' . $index .' of ' . count($images) . '<br />';

if ( $index > 0 ) {
 $output .= get_image_link('<<', 0);
 $output .= ' | ' . get_image_link('Prev', $index-1);
} else {
 $output .= '<< | Prev';
}

$output .= ' | ' . get_table_link('Up', $index, 5);

if ( $index < count($images) ) {
 $output .= ' | ' . get_image_link('Next', $index+1);
 $output .= ' | ' . get_image_link('>>', count($images));
} else {
 $output .= ' | Next | >>';
}

$output .= '</h4>';

  最后创建一个简单的 HTML 容器,将其命名为 expand.php。

  清单 7. get_image 导航

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Creating a simple picture album viewer</title>

<style type="text/css">
body { text-align: center }
table.image_table { margin: 0 auto 0 auto; width: 700px;
padding:10px; border: 1px solid #ccc; background: #eee; }
table.image_table td { padding: 5px }
table.image_table a { display: block; }
table.image_table img { display: block; width: 120px;
padding: 2px; border: 1px solid #ccc; }
</style>

</head>
<body>

<h1>Creating a simple picture album viewer</h1>
<?php

$index = isset($_REQUEST['index']) ? $_REQUEST['index'] : 0;
echo get_image($index);

?>
</body>
</html>

  这样我们就完成了相册。用户可以看到所有的图片,而且很容易导航。自然,用户可以来回切换,甚至能通过书签功能返回喜欢的图片。



TOP

结合AJAX进行PHP开发之入门(3)

添加 Sajax

  现在相册提供了基本的导航功能,目录中的图像添加了索引。下面您将看到添加 Sajax 能够改进编程和用户体验。

  这里假设您对 Ajax 有基本的了解,最好还熟悉 Sajax 的基础知识(请参阅 参考资料 中的教程)。

  Sajax、Ajax 与传统 Web 应用程序
 
  现在我们已经使用标准的 Web 开发模型开发了应用程序。两项主要功能是分页器和图像查看器,它们分别对应不同的 PHP 文件。参数作为 HTTP GET 请求传递给脚本,脚本直接向 Web 客户机返回页面。


  Web 开发社区的人都知道,Ajax 允许向服务器发出异步的辅助请求,并直接在网页中显示结果(如图 4 所示)。不幸的是,即便最简单的 Ajax 应用程序实现起来也是一项大任务。因为 Ajax 不是标准化的技术,Internet Explorer 和其他浏览器(如 Firefox、Safari)的实现是不同的。此外,程序员至少要编写三个函数才能实现一个功能,这三个函数是:发送 HTTP 请求的初始 Javascript,返回响应的 PHP 脚本,以及另一个处理这些响应的 Javascript 函数。


  建立在 Ajax 库之上的 Sajax 通过运用简单的启发式方法大大简化了这一过程:Web 客户机需要访问的每个 PHP 函数都由 Sajax “导出”。如果有一个名为 foo_bar() 的 PHP 函数,那么 Sajax 会把该函数导出为 Javascript 函数 x_foo_bar()。客户机对 x_foo_bar() 的任何调用都会自动转发给服务器上的 foo_bar(),输出则传递给另一个 Javascript 函数。清单 8 中的简短页面示范了这种功能。运行这个例子需要下载 Sajax 库(请参阅 参考资料)。

  清单 8. Sajax 的应用

<?php
require("Sajax.php");

function foo_bar ( $param ) {
 return "You typed: $param";
}

$sajax_request_type = "GET"; // Set HTTP request type to GET
sajax_init(); // Prepare Sajax
sajax_export("foo_bar"); // foo_bar can now be called by client
sajax_handle_client_request(); // Discussed below
?>
<html>
<head>
<script language="javascript">
<? sajax_show_javascript(); ?>
</script>
</head>
<body>
<form >
<input type="text" name="input" />
</form>
</body>
</html>

  如果打开清单 8 中的页面,在输入框中输入一些内容然后单击 Enter,那么输入内容就会在一个警告框中显示出来。但在这个看似简单的网页背后,x_foo_bar() Javascript 函数将远程调用 foo_bar() 函数,并把响应传递给 Javascript 内置函数 alert()。每个 Sajax 导出函数的最后一个参数都是一个响应处理程序,负责处理 foo_bar() 的输出。

  这个例子还说明了 Sajax 快速开发的另一个重要特性:不需要每个函数都有一个单独的文件,页面实际上调用的是其自身,因此更便于跟踪函数的调用(如图 5 所示)。x_foo_bar() 函数直接向页面发回 Ajax 请求,在请求中包含函数名和参数。关键是 sajax_handle_client_request() 函数,它截获所有的 Sajax 调用并自动对它们进行处理。



图  使用 Sajax 客户机可通过一个页面访问服务器端的多个函数

TOP

结合AJAX进行PHP开发之入门(4)

将 Sajax 连接到相册

  利用刚刚创建的代码,我们将用 Sajax 迅速把相册从多页面应用程序转化成活动的 Ajax 应用程序。

  因为相册主要有两个函数,get_table() 和 get_image(),这也是需要用 Sajax 导出的全部函数。事实上,为了通过 Sajax 调用这些函数,这些函数本身基本上不需要修改,很快我们就会看到,我们只需要修改生成的链接即可。

  清单 9. Sajax 相册的头部

<?php
require("Sajax.php");

function get_image () { } // Defined later
function get_thumbs_table () { } // Defined later

// Standard Sajax stuff. Use Get, and export two
// main functions to javascript
$sajax_request_type = "GET";
sajax_init();
sajax_export("get_thumbs_table", "get_image");
sajax_handle_client_request();
?>

  对于本文而言,文档主体部分很简单。我们将使用 div 和 window 的 id 来显示服务器的输出。

  清单 10. 显示服务器输出的 div 和 window id

<body>
<h1>Sajax photo album</h1>
<div id="window"></div>
</body>

  最后还要编写 Javascript 回调函数。该例中,因为所有的服务器输出都直接输出到 window div 标记,所以可以重复使用简单的回调函数。将回调函数添加到 Sajax 函数调用中,就可以得到头(head)。

  清单 11. 简单的头

<head>
<title>Creating a Sajax photo album</title>
<style type="text/css">
body { text-align: center }
div#window { margin: 0 auto 0 auto; width: 700px;
padding: 10px; border: 1px solid #ccc; background: #eee; }
table.image_table { margin: 0 auto 0 auto; }
table.image_table td { padding: 5px }
table.image_table a { display: block; }
table.image_table img { display: block; width: 120px
padding: 2px; border: 1px solid #ccc; }
img.full { display: block; margin: 0 auto 0 auto;
width: 300px; border: 1px solid #000 }
</style>

<script language="javascript">
<? sajax_show_javascript(); ?>

// Outputs directly to the "window" div
function to_window(output) {
 document.getElementById("window").innerHTML = output;
}

window.onload = function() {
 x get table to window);
};

</script>
</head>

  最后一步是保证应用程序中的所有链接都是自定义的 Sajax 调用。只需要取上一节中的代码并作如下替换:href="index.php?start=0&step=5" 变为 ,href="expand.php?index=0" 变为 。

  并在相应的函数中做同样修改: get_image_link() 和 get_table_link()。这样向 Sajax 的转化就完成了(如图 6 所示)。所有链接都变成了与远程 PHP 调用对应的 Javascript 调用,PHP 使用 Javascript 响应处理程序 to_window() 直接输出到页面。

  整个应用程序都包含在一个页面中,还可以把其余功能(get_table()、 get_image() 等)放在不能从 Web 访问的单独的库文件中。在大多数 Ajax 应用程序中,每个发往服务器的请求都需要由单独的脚本处理,或至少需要编写一个非常庞大的处理程序脚本来重定向请求。将所有这些文件都集中到一起可能非常麻烦。使用 Sajax 永远只需要一个文件,在该文件中只需定义我们使用的函数即可。Sajax 代替了处理程序脚本。


  可以看到 URL 仍然保持不变,并带来了更多愉快的用户体验。window div 显示在一个灰色的框中,通过 Sajax 生成的内容非常清楚。脚本不一定要知道自身或者它在服务器上的位置,因为所有的链接最终都成为直接对页面自身的 Javascript 调用。因此我们的代码能够很好的模块化。我们只需要保持 Javascript 和 PHP 函数在同一个页面上即可,即使页面位置发生了变化也没有关系。

TOP

结合AJAX进行PHP开发之入门(5)

扩展相册

  使用 Sajax 把我们的相册变成活动的 Web 应用程序如此轻而易举,我们要再花点时间添加一些功能,进一步说明 Sajax 如何使从服务器检索数据变得完全透明。我们将为相册添加元数据功能,这样用户就能为他们的图片添加说明。

  元数据

  没有上下文说明的相册是不完整的,比如照片的来源、作者等。为此我们要将图像集中起来创建一个简单的 XML 文件。根节点是 gallery,它包含任意多个 photo 节点。每个 photo 节点都通过其 file 属性来编号。在 photo 节点中可以使用任意多个标记来描述照片,但本例中只使用了 date、locale 和 comment。

  清单 12. 包含元数据的 XML 文件

<?xml version="1.0"?>
<gallery>
 <photo file="image01.jpg">
  <date>August 6, 2006</date>
  <locale>Los Angeles, CA</locale>
  <comment>Here's a photo of my favorite celebrity</comment>
 </photo>
 <photo file="image02.jpg">
  <date>August 7, 2006</date>
  <locale>San Francisco, CA</locale>
  <comment>In SF, we got to ride the street cars</comment>
 </photo>
 <photo file="image03.jpg">
  <date>August 8, 2006</date>
  <locale>Portland, OR</locale>
  <comment>Time to end our road trip!</comment>
 </photo>
</gallery>

  文件的解析不在本文讨论范围之列。我们假设您能够熟练使用 PHP 中众多 XML 解析方法中的一种。如果不熟悉的话,建议阅读 参考资料中的文章。我们不再浪费时间解释如何将该文件转化成 HTML,作为一个练习,读者可以自己了解下面的代码如何使用 XML 文件并生成 HTML。清单 13 中的代码使用了 PHP V5 中自带的 SimpleXML 包。

  清单 13. 元数据函数

function get_meta_data ( $file ) {

 // Using getimagesize, the server calculates the dimensions
 list($width, $height) = @getimagesize("images/$file");
 $output = "<p>Width: {$width}px, Height: {$height}px</p>";

 // Use SimpleXML package in PHP_v5:
 // http://us3.php.net/manual/en/ref.simplexml.php
 $xml = simplexml_load_file("gallery.xml");

 foreach ( $xml as $photo ) {
  if ($photo['id'] == $file) {
   $output .= !empty($photo->date) ? "<p>Date taken:{$photo->date}</p>" : '';
   $output .= !empty($photo->locale) ? "<p>Location:{$photo->locale}>/p>" : '';
   $output .= !empty($photo->comment) ? "<p>Comment:{$photo->comment}</p>" : '';
  }
 }
 return $output;

  要注意的是,get_meta_data() 函数中还使用 getimagesize()(一个核心 PHP 函数,不需要 GD)计算图像的大小。

  再回到 get_image() 函数,它包含由 get_image_list() 生成的文件名的列表。查找元数据只需要将文件名传递给该函数即可。

  清单 14. 添加元数据

function get_image ( $index ) {
 $images = get_image_list ( 'images' );

 // ...

 $output .= '<img src="images/' . $images[$index] . '" />';
 $output .= '<div id="meta_data">' .
 get_meta_data( $images[$index] ) . '</div>';
 return $output;
}

  重新打开页面将看到服务器请求的结果。图 7 显示了带有元数据的放大的图像。


  结束语

  我们看到,使用 Sajax 可以消除客户机和服务器之间的障碍,程序员能够进行无缝远程函数调用而不用担心传输层、HTTP GET 和 POST 请求。我们可以花更多时间编写提供数据的 PHP 脚本以及表示层和控制层的 Javascript。在这个相册例子中,我们让客户机直接连接到图像数据库。通过添加简单的元数据,我们看到让用户直接访问服务器上的信息是多么简单,无需担心协议的问题。

  与所有的 Ajax 应用程序一样,我们的相册也有一个致命的弱点:没有使用浏览器的 “访问历史”,因为破坏了后退按钮的功能。在 “利用 PHP 开发 Ajax 应用程序” 系列的第 2 部分中,我们将通过实现历史记录缓冲和状态跟踪机制来解决这个问题。

TOP

发新话题