第11章集成 Ajax.docx
- 文档编号:20132544
- 上传时间:2023-04-25
- 格式:DOCX
- 页数:30
- 大小:42.08KB
第11章集成 Ajax.docx
《第11章集成 Ajax.docx》由会员分享,可在线阅读,更多相关《第11章集成 Ajax.docx(30页珍藏版)》请在冰豆网上搜索。
第11章集成Ajax
第11章集成Ajax
在Web2.0的应用中,经常碰到诸如在客户端交互作用、复杂视觉效果及异步通讯之类的问题,这些功能都要用javascript去实现。
但是,用javascript编程是很繁琐且难以测试的。
为了自动完成许多要用javascript编写的常用功能,symfony在模板中提供了一组完整的辅助函数。
许多客户端功能甚至连一行javascript语句都不用写就可以开发出来,开发人员只需要考虑他们想要达到的效果,而复杂的语法和兼容性问题则交给symfony去处理。
本章介绍以下内容,这些内容将会帮助你了解如何用symfony提供的工具来编写客户端代码:
∙在symfony模板中,基本的javascript辅助函数输出与标准兼容的
但是javascript的最主要应用并不是编写代码块,而是用超链接去触发某个具体脚本。
例11-2显示了link_to_function()辅助函数的使用。
例11-2利用link_to_function()辅助函数,一个链接可以触发javascript代码。
phpecholink_to_function('Clickme!
',"alert('foobar')")?
>
=>
和link_to()辅助函数一样,第三个参数可以为标记加入选项。
NOTE与link_to()相似的还有button_to(),你可以调用button_to_function()辅助函数通过一个按钮(
如果你还想要一个可点击的图片,只要调用link_to_function(image_tag(“myimage”),“alert(‘foobar`)”)即可。
更新一个DOM元素
更新页面中的一个元素是动态界面经常要解决的问题。
例11-3是为此而经常编写的代码。
例11-3用javascript更新一个元素
phpechojavascript_tag('
document.getElementById("indicator").innerHTML=
"Dataprocessingcomplete";
')?
>
symfony为此提供了一个名为update_element_function()的辅助函数,用于生成javascript代码而不是html代码。
例11-4是一个示例。
例11-4在javascript代码块中用update_element_function()辅助函数更新一个元素
phpechojavascript_tag('
update_element_function("indicator",array(
"content"=>"Dataprocessingcomplete",
'))
)?
>
你也许在想:
这条辅助函数语句和真正的javascript代码一样长,那使用它有什么特别的好处呢?
好处在于它的可读性。
例如,如果你想根据某种条件在一个元素之前或之后插入内容,或者不是更新元素内容而是删除一个元素,或者不做任何处理时,javascript代码将会变得相当混乱,但是利用update_element_function(),却可以像例11-5那样保持清晰易读。
例11-5update_element_function()辅助函数的选项
//在indicator元素之后插入内容
update_element_function('indicator',array(
'position'=>'after',
'content'=>"Dataprocessingcomplete",
));
//如果$condition成立,则删除indicator之前的元素
update_element_function('indicator',array(
'action'=>$condition?
'remove':
'empty',
'position'=>'before',
))
可以看出,这个辅助函数让你的模板比任何javascript代码都要容易理解,而且你只要使用一种语法就可以处理相似的行为。
这也是为什么这个辅助函数名字这样长的原因:
无需额外的说明,它就可以充分地解释自身的用途。
轻松地降级(GracefulDegradation)
用
symfony用一个辅助函数从另一方面进行补充这个功能,也就是利用它可以让代码仅在支持javascript的浏览器中执行。
例11-6中,显示了用if_javascript()和end_if_javascript()实现这种降级的用法:
例11-6利用if_javascript()辅助函数轻松地降级
phpif_javascript();?
>
YouhaveJavaScriptenabled.
phpend_if_javascript();?
>
Youdon'thaveJavaScriptenabled.
NOTE调用if_javascript()和end_if_javascript()时,不需要用echo.
Prototype
Prototype是一个优秀的javascript库,它扩展了客户端脚本的能力,增加了开发者想要的功能,并且提供了新的机制去操作DOM,该项目的网站是http:
//prototypejs.org/。
symfony框架中绑定了Prototype文件,在每个项目的web/sf/prototype目录中可以找到它的文件。
这样只要在你的action中增加下列代码就可以使用Prototype:
$prototypeDir=sfConfig:
:
get('sf_prototype_web_dir');
$this->getResponse()->addJavascript($prototypeDir.'/js/prototype');
或者在view.yml文件中加入:
all:
javascripts:
[%SF_PROTOTYPE_WEB_DIR%/js/prototype]
NOTE因为symfonyAjax辅助函数(下一节介绍)需要用到Prototype,所以只要你用到Prototype库,它就会自动被包含进来。
也就是说,如果你的模板调用一个_remote辅助函数,你无需在你的响应里手工添加PrototypeJavascript。
一旦你载入了Prototype库,就可以利用它为javascript核心增加的新函数。
本书的主要目的不是讲述这些函数,你可以很容易在互联网上找到所需的文档,以下是几个有关的网站:
∙Particletree:
∙SergioPereira:
∙Script.aculo.us:
http:
//wiki.script.aculo.us/scriptaculous/show/Prototype
Prototype新增的Javascript函数之一是$()函数。
简单地说,这个函数可以看成是document.getElementById()函数的缩写,但它有更强的功能。
例11-7给出了一个应用的例子。
例11-7利用$()函数根据DOM的元素ID取得元素值。
node=$('elementID');
//相当于
node=document.getElementById('elementID');
//也可以一次检索多个元素
//在本例中返回值是一个由DOM元素组成的数组。
nodes=$('firstDiv','secondDiv');
Prototype还提供了javascript核心真正缺乏的一个方法,这个方法返回所有CSSclassName属性等于它接收的参数的DOM元素组成的数组:
nodes=document.getElementByClassName('myclass');
当然你不太会用到这个函数,因为Prototype提供了一个更强大的$$()函数。
这个函数根据CSS选择器返回一个由DOM元素组成的数组。
所以前面的调用可以写成如下形式:
nodes=$$('.myclass');
凭借CSS选择器的作用,你可以根据class、ID、父子关系和前后关系去解析DOM,这比通过XPath表达式去解析更为简单。
你甚至可以用一个混合了所有这些选择器的复杂选择器去访问对应的元素。
nodes=$$('bodydiv#mainulli.lastimg>span.legend');
Prototype增强Javascript语法功能的最后一个例子是数组迭代。
它为Javascript定义匿名函数和闭包(closure)(译者注:
如果在一个javascript函数体中又出现一个函数定义时,称此函数为闭包(closure))功能提供了和PHP同样的简化形式。
如果你编写javascript代码,可能会大量用到这个功能。
varvegetables=['Carrots','Lettuce','Garlic'];
vegetables.each(function(food){alert('Ilove'+food);});
因为用Prototype编写Javascript比纯手工编写更为有趣,并且因为Prototype也是symfony的一个组成部分,所以你应该花些时间去研究它的文档。
Ajax辅助函数
如果你想在服务器端用PHP脚本去更新页面中的元素内容,而不想用javascript去更新(如例11-5所示),这样你可以根据一个服务器的响应来改变页面的某个部分,那该怎么做呢?
remote_function()辅助函数就可以完成这个任务,如例11-8所示:
例11-8应用remote_function()辅助函数
phpechojavascript_tag(
remote_function(array(
'update'=>'myzone',
'url'=>'mymodule/myaction',
))
)?
>
NOTEurl参数既可以包含一个内部URI(module/action?
key1=value1&…),也可以包含一个路由规则名,就像在一个标准的url_for()中那样。
当你调用这个函数时,这段脚本就会根据mymodule/myaction动作的请求或响应,去更新id为myzone的元素。
这种交互就是Ajax,也正是高度可交互的web应用的核心。
Wikipedia(http:
//en.wikipedia.org/wiki/AJAX)描述了Ajax的特点:
Ajax让页面只和服务器交换很少量的数据,因而每当用户改变页面时,不需要重新导入整个网页,而使得页面的响应更快。
也就是说增强了网页的交互性,速度和可用性。
Ajax依赖于javascript对象XMLHttpRequest,该对象的行为如同一个隐藏的帧,你可以从一个服务器请求更新它并且重用它去操纵页面的剩余部分。
这是一个相当底层的对象,不同的浏览器用不同的方法去处理它。
所幸的是,Prototype封装了所有Ajax需要的代码并提供了一个更为简化的Ajax对象,symfony就借助于这个对象。
这也是为什么当你在一个模板中使用Ajax辅助函数时,Prototype就会自动装入的原因。
CAUTION如果远程动作的URL不属于当前页所在的域,Ajax辅助函数将不工作。
这既是出于安全考虑,也受到浏览器禁止远程动作通过的限制。
一个Ajax交互由三个部分组成:
一个调用者(链接、按钮、表单、时钟或其它用户可以操纵以启动动作的任何控件),一个服务器动作和页面中的一个显示动作响应的区域。
如果远程动作返回的数据还要被客户端的Javascript函数处理,你可以创建更复杂的交互。
symfony提供了多个名字中包含remote的辅助函数,以便你在模板中插入Ajax交互。
它们使用共同的语法,可以将所有的Ajax参数放进一个关联数组中。
注意,Ajax辅助函数输出的是HTML,而不是Javascript。
SIDEBARAjax动作如何工作?
远程函数被调用的动作就是一个通常的动作。
与其它动作一样,它们可以被路由,可以确定用哪个视图提交它们返回的响应,也可以向模板传递参数以及改变模型等。
但是,当通过Ajax调用动作时,动作将返回true给下面的调用:
$isAjax=$this->isXmlHttpRequest();
symfony知道动作处于Ajax环境中,因而能够对响应做相应的处理。
因此,在默认情况下,开发环境中的Ajax动作不包含web调试工具栏,而且也会跳过装饰处理(默认情况下,模板不会被包含在布局中)。
如果你想装饰Ajax的视图,你需要在模块的view.yml文件中,为这个视图明确设置has_layout的值为true。
还有一点:
因为响应性在Ajax的交互中至关重要,所以如果响应不是非常复杂,最好不要创建视图,而是直接从动作返回响应。
这样你可以在动作中用renderText()方法,直接跳过模板而加速Ajax请求。
Ajax链接
在Web2.0应用中,Ajax链接是Ajax交互应用的主要内容。
显而易见,link_to_remote()辅助函数就可以输出一个调用远程函数的链接。
除了第二个参数是一个由Ajax选项组成的关联数组以外,其他语法类似于link_to()。
例11-9是一个示例。
例11-9利用ink_to_remote()辅助函数得到Ajax链接
phpecholink_to_remote('Deletethispost',array(
'update'=>'feedback',
'url'=>'post/delete?
id='.$post->getId(),
))?
>
在这个例子中,点击Deletethispost链接就会在后台发出一个对post/delete的调用。
从服务器返回的响应将出现在id为feedback的元素中。
图11-1显示了运行的过程。
图11-1用链接触发一个远程更新
对于链接,你可以用图片代替字符串,用规则名代替内部的模块/动作URL,还可以将选项加进标记的第三个参数中。
如例11-10所示。
例11-10link_to_remote()辅助函数的选项