锁定老帖子 主题:Ajax一统天下之Dojo整合篇
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2006-11-19
目前我们公司已经形成一套基于Ajax的完整的产品,封装了自己的Ajax前后台通讯机制以及提供了可重用的客户端组件,我尝试了一下将我们的产品与Dojo Toolkit进行整合。下面是我的做法,整合的是Dojo ComboBox Widget,它实际上是一个Auto Completion组件,类似Google Suggest。 从Dojo提供的测试类test_ComboBox.html入手,加debugger进行跟踪调试,理清Dojo Widget的加载流程。 经过跟踪调试,对Dojo的Widget有了一个大致的了解:首先是加载当前需要的JavaScript文件,然后对整个html页面进行解析。在页面上使用widget有三种方式:一种就是在html元素上添加一些dojo能解析的属性,如 <select dojoType="combobox" style="width: 300px;" name="foo.bar1" autocomplete="false" onValueChanged="setVal1" > 其中的dojoType,autocomplete, onValueChanged都是dojo能够识别的属性,这个有些类似typestry的做法。第二种就是使用DojoML的写法: <dojo:combobox style="width: 300px;" name="foo.bar1" autocomplete="false" onValueChanged="setVal1" /> 这种写法有些变态,跟jsp中的自定义标签基本就是一回事,只是把解析的过程从后台移到了前台来做,后来看到有些框架也这么干,也就没话说了。 还有一种写法是使用javascript在页面加载完成之后,在指定的html元素创建widget: var combo; dojo.addOnLoad(init); function init(){ combo = dojo.widget.createWidget("dojo:ComboBox", {name:"prog",autocomplete:false,dataUrl:"comboBoxData.js"}, dojo.byId("progCombo")); } 在对元素解析创建的时候同时利用dojo定义的combobox html模版以及css模版完成在页面中插入最终的combobox控件的目的。 接下来看看Dojo ComboBox如何通过ajax与后台通讯,Dojo ComboBox提供了两种自动完成方式:一种是将所有的数据下载到前台缓存,然后在前台根据用户输入的数据从缓存中匹配出自动完成所需要的数据列表。另外一种就是根据用户每次输入的数据实时向后台发送请求获得要自动完成的数据,当然这个数据也会以用户输入的内容为key,以得到的数据为value进行缓存。对于两种方式,Dojo通过不同的DataProvider来实现(dojo.widget.incrementalComboBoxDataProvider和dojo.widget.basicComboBoxDataProvider),这一点非常精妙,让我非常佩服。而这两个类都是通过dojo.declare(“className”, “parentClassName”, constructor, declarationBody)这种方式来做的,这个也和我们以往的做法有别。总之就是比较精妙啦! Dojo向后台发送请求的过程封装在dojo.io.bind()这个方法中,而我们有自己的一套前后台通讯机制,因为必须想办法将dojo.io.bind()替换成我们的做法来达到最终整合的目的,因为Dojo ComboBox的数据交互都是封装在DataProvider里面的,因为我们只需要实现自己的DataProvider就可以搞定了,这样我们无须修改Dojo的源代码,而且还可以使用Dojo的继承机制,从已有的DataProvider集成复写掉我需要替换的方法,这让我有了写Java的感觉。 dojo.declare( "dojo.widget.incrementalDoradoComboBoxDataProvider", dojo.widget.incrementalComboBoxDataProvider, null, { //要替换的方法,使用自己的通讯机制 startSearch: function(/*String*/ searchStr, /*Function*/ callback){ if(this._inFlight){ // FIXME: implement backoff! } var cmd = getControl(this.searchUrl); cmd.parameters().setValue("searchString", searchStr); var _this = this; EventManager.addDoradoEvent(cmd, "onSuccess", function(command){ _this._inFlight = false; //convention: //1.the key must be "result" //2.the data format must be [["Alabama","AL"],["Alaska","AK"]] or [{"Alabama":"AL"},{"Alaska":"AK"}] var data = dj_eval(command.outParameters().getValue("result")); if(!dojo.lang.isArray(data)){ var arrData = []; for(var key in data){ arrData.push([data[key], key]); } data = arrData; } _this._addToCache(searchStr, data); callback(data); } ); cmd.execute(); this._inFlight = true; } } ); 通过上面的处理,就可以使用我们自己的前后台通讯机制来完成请求数据的目的。 接下来就是生成我们的页面,添加dojo加载js代码的脚本: <script type="text/javascript" src="./dojo/dojo.js"></script> <script type="text/javascript"> dojo.require("dojo.widget.ComboBox"); // 注意这里有一个定位的问题,查找路径必须加"..", // 因为dojo在查找DoradoComboBox.js的时候会从"/dojo"而不是"/"目录开始查找 // 最终使用xmlhttp加载的路径是/dojo/../adapter/dojo/widget/DoradoComboBox.js dojo.setModulePrefix("adapter.dojo.widget","../adapter/dojo/widget"); dojo.require("adapter.dojo.widget.DoradoComboBox"); </script> 下面要加载的控件部分html代码: <input dojoType="ComboBox" dataUrl="cmdComboboxSearch" dataProviderClass = "dojo.widget.incrementalDoradoComboBoxDataProvider" style="width: 200px;" name="sample2" autocomplete="false" > 这样我们的整合工作就完成了,对了还有文件的目录结构: Webapp |--adapter(存放所有用于整合的js文件) |------dojo |---------widget |-----------DoradoComboBox.js |--dojo(dojo的所有js文件) |------src |------dojo.js |--js(我们自己组件库的js文件) |--WEB-INF 结论 通过扩展之后还是发现了不少问题: 1、由于集成的两套东西都会在Object.prototype, Array.prototype, Function.prototype上加一些自己的东西,因此这样非常容易带来命名上的冲突,已经碰到这个问题。 2、由于二者都会使用一些全局性的函数,变量等,这样也会存在潜在的冲突,不过目前还没有碰到。 3、多套js库要同时加载,客户端的压力是不是大了些?性能可以接受吗?目前还没有测试不得而知。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2006-11-20
前段时在这上面吵得很凶的JSVM2可以做得到: http://jsvm.org/forums/ 上面有对YUI、prototype和dojo的整合,但不完整
|
|
返回顶楼 | |
发表时间:2006-11-22
整合要考虑一下,下载的速度,一个prototype就已经有48K其他的加一下,可能会上百K这对网络不是什么好事啊,
|
|
返回顶楼 | |
发表时间:2006-11-22
chpn 写道 前段时在这上面吵得很凶的JSVM2可以做得到: http://jsvm.org/forums/ 上面有对YUI、prototype和dojo的整合,但不完整
看了一下JSVM2与dojo整合的部分,里面通过extmodel机制来实现,我不知道extmodel的具体机制是怎么样的,但是看了一下对combobox的扩展,好像是对dojo的combobox采用JSVM2的方式重写了一遍,而且dojo的很多部分都是调用JSVM2来改写dojo的东西,这样整合之后,如果dojo更新了,JSVM2改写的部分是不是也要重写一遍? 引用 通过extmodules的方式将dojo完整地集成到jsvm中
主要做的改动如下: 1、修正了dojo.js中部分关于系统路径的代码以正确解析widget 2、用JSVM2的方式实现了dojo一部分底层包包括 dojo.lang,dojo.string,dojo.uri,dojo.debug等... 并且实现了dojo.html,dojo.dom,dojo.lfx等,支持dojo的Animation以及事件模型。 不得不佩服JSVM作者的能力 |
|
返回顶楼 | |
发表时间:2006-11-22
guoshiguan 写道 整合要考虑一下,下载的速度,一个prototype就已经有48K其他的加一下,可能会上百K这对网络不是什么好事啊,
所以应该考虑dojo的方式按需加载,而不是统统的一次性全部加载进来 |
|
返回顶楼 | |
发表时间:2006-11-23
macrochen 写道 guoshiguan 写道 整合要考虑一下,下载的速度,一个prototype就已经有48K其他的加一下,可能会上百K这对网络不是什么好事啊,
所以应该考虑dojo的方式按需加载,而不是统统的一次性全部加载进来 同意,但是现在遇到一个这样的问题。 在dojo.io.bind中可以设置text/javascript类型的交互模式,就像<AJAX in Action>里提到的以脚本为核心的交互,这对于实现前端动态的页面效果会带来极大的好处,而且不暴露JS内容,但这样必然增加流量,如何权衡? |
|
返回顶楼 | |
发表时间:2006-11-23
flyromza 写道 在dojo.io.bind中可以设置text/javascript类型的交互模式,就像<AJAX in Action>里提到的以脚本为核心的交互,这对于实现前端动态的页面效果会带来极大的好处,而且不暴露JS内容,但这样必然增加流量,如何权衡? 下载html,xml流量就会比下载javascript要小吗? |
|
返回顶楼 | |
发表时间:2006-12-07
看来你真是得了Appeon的真传啊。
|
|
返回顶楼 | |
发表时间:2006-12-11
个人觉得AJAX在有些方面反而会影响到系统的速度.可以在一些特效方面使用,如果整个系统都是用它来做,有点不敢想象.
|
|
返回顶楼 | |
发表时间:2006-12-12
norwaywoods 写道 看来你真是得了Appeon的真传啊。
很可惜,appeon的那套东西都差不多忘光了,是廖健吗?在北京混的如何? |
|
返回顶楼 | |