Ajax一统天下之Dojo整合篇


Posted in Javascript onMarch 24, 2007

随着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库要同时加载,客户端的压力是不是大了些?性能可以接受吗?目前还没有测试不得而知。

Javascript 相关文章推荐
jquery ajax 同步异步的执行示例代码
Jun 23 Javascript
php对mongodb的扩展(小试牛刀)
Nov 11 Javascript
如何使用json在前后台进行数据传输实例介绍
Apr 11 Javascript
关于jquery.validate1.9.0前台验证的使用介绍
Apr 26 Javascript
在JavaScript中访问字符串的子串
Jul 07 Javascript
设计模式中的facade外观模式在JavaScript开发中的运用
May 18 Javascript
JavaScript实现的选择排序算法实例分析
Apr 14 Javascript
jQuery插件Validation表单验证详解
May 26 jQuery
Vue面试题及Vue知识点整理
Oct 07 Javascript
js 实现 list转换成tree的方法示例(数组到树)
Aug 18 Javascript
使用uni-app开发微信小程序的实现
Dec 13 Javascript
js实现网页随机验证码
Oct 19 Javascript
dojo 之基础篇(三)之向服务器发送数据
Mar 24 #Javascript
dojo 之基础篇(二)之从服务器读取数据
Mar 24 #Javascript
dojo 之基础篇
Mar 24 #Javascript
jQuery使用手册之 事件处理
Mar 24 #Javascript
jQuery使用手册之三 CSS操作
Mar 24 #Javascript
jQuery使用手册之二 DOM操作
Mar 24 #Javascript
jQuery使用手册之一
Mar 24 #Javascript
You might like
php使用正则表达式提取字符串中尖括号、小括号、中括号、大括号中的字符串
2020/04/05 PHP
php中使用key,value,current,next和prev函数遍历数组的方法
2015/03/17 PHP
php简单实现查询数据库返回json数据
2015/04/16 PHP
php生成二维码
2015/08/10 PHP
PHP的时间戳与具体时间转化的简单实现
2016/06/13 PHP
php 截取GBK文档某个位置开始的n个字符方法
2017/03/08 PHP
PHP优化之批量操作MySQL实例分析
2020/04/23 PHP
很酷的javascript loading效果代码
2008/06/18 Javascript
jquery提取元素里的纯文本不包含span等里的内容
2013/09/30 Javascript
js中substring和substr的定义和用法
2014/05/05 Javascript
jQuery点击改变class并toggle及toggleClass()方法定义用法
2015/12/11 Javascript
JavaScript弹出对话框的三种方式
2016/03/23 Javascript
JS中页面与页面之间超链接跳转中文乱码问题的解决办法
2016/12/15 Javascript
微信小程序对接七牛云存储的方法
2017/07/30 Javascript
jQuery中each循环的跳出和结束实例
2017/08/16 jQuery
详谈js对url进行编码和解码(三种方式的区别)
2017/08/16 Javascript
vue双花括号的使用方法 附练习题
2017/11/07 Javascript
AngularJS使用Filter自定义过滤器控制ng-repeat去除重复功能示例
2018/04/21 Javascript
原生js实现3D轮播图
2020/03/21 Javascript
vue 实现 rem 布局或vw 布局的方法
2019/11/13 Javascript
Vue动态加载图片在跨域时无法显示的问题及解决方法
2020/03/10 Javascript
[42:48]完美世界DOTA2联赛PWL S3 Magma vs INK ICE 第二场 12.11
2020/12/16 DOTA
在Python的Django框架中显示对象子集的方法
2015/07/21 Python
利用python微信库itchat实现微信自动回复功能
2017/05/18 Python
浅谈python配置与使用OpenCV踩的一些坑
2018/04/02 Python
Python中浅拷贝copy与深拷贝deepcopy的简单理解
2018/10/26 Python
python如何实现word批量转HTML
2020/09/30 Python
详解css3 mask遮罩实现一些特效
2018/10/24 HTML / CSS
AE美国鹰美国官方网站:American Eagle Outfitters
2016/08/22 全球购物
Richards网上商店:当代时尚,遍布巴西
2019/11/03 全球购物
双立人美国官方商店:ZWILLING集团餐具和炊具
2020/05/07 全球购物
JAVA和C++区别都有哪些
2015/03/30 面试题
如何利用find命令查找文件
2016/11/18 面试题
高中班长自我鉴定
2013/12/20 职场文书
PostgreSQL存储过程实用脚本(二):创建函数入门
2021/04/05 PostgreSQL
mysql中between的边界,范围说明
2021/06/08 MySQL