Ajax一统天下之Dojo整合篇
所属分类:
网络编程 / JavaScript
阅读数:
1626
收藏 0赞 0分享
随着Ajax应用越来越多,各种Ajax Library(Prototype),Ajax Framework(DWR),Ajax Toolkit(Dojo,YUI)也日渐丰富起来,有没有办法将这些结合起来呢?类似Spring的做法,当然我没法整出一个IoC的微内核将各种Ajax“粘合”起来,但是将这些Ajax可重用的组件加以整合应该是没有问题的,这样即可以避免重复发明轮子,还可以针对各种Ajax进行扬长避短,形成一套比较全面的Ajax解决方案。同时也增加了开发人员选择自己熟悉Ajax组件的灵活性。
目前我们公司已经形成一套基于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库要同时加载,客户端的压力是不是大了些?性能可以接受吗?目前还没有测试不得而知。
ES6中Array.find()和findIndex()函数的用法详解
ES6为Array增加了find(),findIndex函数。find()函数用来查找目标元素,找到就返回该元素,找不到返回undefined,而findIndex()函数也是查找目标元素,找到就返回元素的位置,找不到就返回-1。下面通过实例详解,需要的朋友参考下吧
收藏 0赞 0分享
JS闭包的几种常见形式实例详解
本文通过实例代码给大家详细介绍了js闭包的几种常见形式,代码简单易懂,非常不错,具有参考借鉴价值,需要的朋友参考下
收藏 0赞 0分享
Javascript 严格模式use strict详解
严格模式:由ECMA-262规范定义的JavaScript标准,对javascrip的限制更强。这篇文章主要介绍了Javascript 严格模式use strict详解 ,需要的朋友可以参考下
收藏 0赞 0分享
引入JavaScript时alert弹出框显示中文乱码问题
今天在HTML中引入JavaScript文件运行时,alert弹出的提示框中文显示为乱码,怎么解决此问题呢?下面小编给大家带来了引入JavaScript时alert弹出框显示中文乱码问题的解决方法,一起看看吧
收藏 0赞 0分享
Angularjs自定义指令实现分页插件(DEMO)
由于最近的一个项目使用的是angularjs1.0的版本,涉及到分页查询数据的功能,后来自己就用自定义指令实现了该功能,下面小编把实例demo分享到脚本之家平台,需要的朋友参考下
收藏 0赞 0分享
查看更多