转 :xGird,来自jQuery的神器(二):xGrid是如何炼成的

xGird,来自jQuery的神器(二):xGrid是如何炼成的?
之前的一节中,大家应该已经体验到了xGrid这个控件的强大之处,xGird实际上部分地解决了Domino上的两大难题:1、检索,特别是复杂检索的性能,xGrid的检索是可以针对已经下载到缓存中的数据进行的,因此它不仅远远比Domino的FTSearch快,同时也比SQL快!但请注意,在大数据量的情况下,一次性加载也是需要一定的耗时的。

2、分类,OpenNTF上的这个xGrid的例子支持一级分类,但xGrid实际上可以做到多级分类,而且xGrid和dojo.Grid不一样,使用过dojo.Grid的同学应该有感觉,虽然同样是支持json数据的传输,但是如果想做出多级分类,甚至是树形结构的话,dojo.Grid所需要的json数据是一个比较复杂的结构的,产生这样一个结构的json数据要一定的经验和代码量,但xGrid则不一样,它对json的数据格式没有更多的要求,一个简单的2维结构即可(可以理解成是Excel数据,一行一行的),这个的巨大好处是,对于一些应用,你只需要制作一张比较大的视图即可,然后所有的筛选都可以由xGrid完成。

xGrid的确很强大,所以Victor给它冠上了“神器”的称号,这是一个可以大大改变Domino应用的CC,但这个CC为何如此强大?这样的一个CC又是如何设计出来的呢?下面我们将揭开谜底,并希望你能由此受到启发,体会到XPages开发中如何又快又好的设计一个CC。

下面进入正题:
在上一节的回复中,已经有朋友很不满的指出,所谓的xGrid其实是将XPages技术和jqGrid进行了结合,没错!xGrid之所以如此强大的原因在于它基于一个强大的jQuery Plugins--jqGrid,对此Victor绝对没有任何想隐藏的,从我们的题目中,Victor其实已经透露了xGrid来自于jQuery,呵呵。

jqGrid的官方网站为:http://www.trirand.com
另外还有一个非常帮的Demo站点,它的价值更高,在它的上面,你可以对jqGrid的整体功能有一个直观的体验:http://www.trirand.com/blog/jqgrid/jqgrid.html


在继续下面的内容之前,Victor强烈建议大家首先花一点时间在jqGrid Demo站点上完整的浏览体会一下,这很重要,因为Victor想说jqGrid能实现的所有功能,在xGrid都可以实现,我们的第4节的内容就将在xGrid原作者的基础上的,对xGrid进行增强,以实现多级分类和添加、编辑、删除功能,因此大家可以先对jqGrid的所有功能都有一个了解,然后既可以自己直接着手研究如何把jqGrid所有的功能都扩展到xGrid上来,也可以在我们结束了第4节的实战后来进行自己的扩展。另外就是,jqGrid的API真的是非常丰富,不首先对jqGrid的API有一个了解,正版的xGrid可能都吃不透,何况是自己再进行扩展?最后请注意,目前最新的jqGrid版本已经是4.4.1了,Victor第4节的实战内容将以4.4.1为基础,但正版的xGrid应该是4.3.x的版本,例如多层分类的功能在4.4.0之前是没有的。

下面我们从jqGrid上取一段Demo演示的代码,它是jqGrid的一个最基本应用,展示的链接地址是:

首先,Victor申明一点,我无法这里解说jQuery的语法,以及jqGrid的API,学习jQuery的话,国内有一本非常棒的书《锋利的jQuery》,现在已经是第二版了,而且实话实说jQuery的语法真心是比较容易和简洁的;而jqGrid的API,大家可以从jqGrid的官网上进行查询,也可以通过Demo站点一点点摸索,Victor就不做无谓的工作了。
  1. jQuery("#list2").jqGrid({
  2.            url:'server.php?q=2',
  3.      datatype: "json",
  4.           colNames:['Inv No','Date', 'Client', 'Amount','Tax','Total','Notes'],
  5.        colModel:[
  6.                   {name:'id',index:'id', width:55},
  7.                    {name:'invdate',index:'invdate', width:90},
  8.                  {name:'name',index:'name asc, invdate', width:100},
  9.                  {name:'amount',index:'amount', width:80, align:"right"},
  10.             {name:'tax',index:'tax', width:80, align:"right"},         
  11.             {name:'total',index:'total', width:80,align:"right"},               
  12.             {name:'note',index:'note', width:150, sortable:false}               
  13.     ],
  14.           rowNum:10,
  15.           rowList:[10,20,30],
  16.          pager: '#pager2',
  17.            sortname: 'id',
  18.     viewrecords: true,
  19.     sortorder: "desc",
  20.     caption:"JSON Example"
  21. });
  22. jQuery("#list2").jqGrid('navGrid','#pager2',{edit:false,add:false,del:false});
复制代码

下面我们用designer打开ccxGrid,你应该在设计区域可以看到如图中所示的一个类似于卷子,或者专业点说是类似于脚本的一个标志,选中它,对了别忘了上一节的内容,你可以通过左小角的outline看到自己选中的是什么元素,这样下次的时候,你可以通过outline更快地选定这个设计元素,通过outline我们知道了这个设计元素的类型是Output script,在右边的控件栏里你很有可能找不到这个控件,不要着急,我们后面会介绍如何加入这个设计元素,并且这个设计元素的作用是什么。



现在你需要注意的是在Output script这个设计元素的All properties里有一个value值,貌似里面有一些值看起来像是jQuery代码,选中value值,然后点击如图中的按钮,




你可以打开一个代码编辑框,看到如下的代码:

  1. $().ready(function(){
  2.         jQuery("#listxGrid").jqGrid({
  3.                           url:'#{javascript:compositeData.url}',
  4.                         datatype: "json",
  5.                            colNames:#{javascript:compositeData.colNames},
  6.                            colModel:#{javascript:compositeData.colModel},
  7.                         jsonReader: {
  8.                             repeatitems: false,
  9.                             id: '#{javascript:compositeData.colID}',
  10.                             root: function (obj) {
  11.                                 if ($.isArray(obj)) return obj;
  12.                                 if ($.isArray(obj.items)) return obj.items;
  13.                                 return [];
  14.                             },
  15.                             page: function () { return 1; },
  16.                             total: function () { return 1; },
  17.                             records: function (obj) {
  18.                                 if ($.isArray(obj))        return obj.length;
  19.                                 if ($.isArray(obj.items))        return obj.items.length;
  20.                                 return 0;
  21.                             }
  22.                         },
  23.                         gridview: true,
  24.                                         loadonce: #{javascript:compositeData.loadOnce},
  25.                                         ignoreCase: #{javascript:compositeData.ignoreCase},
  26.                         rowNum: #{javascript:compositeData.rowNum},
  27.                                         rowList: #{javascript:compositeData.rowList},
  28.                                         rownumbers: #{javascript:compositeData.showRowNumbers},
  29.                                         height: #{javascript:compositeData.height},
  30.                                         caption: '#{javascript:compositeData.caption}',
  31.                                         pager: '#pagerxGrid',
  32.                                         viewrecords: true,
  33.                                         emptyrecords: '#{javascript:compositeData.emptyRecords}',
  34.                                         sortable:#{javascript:compositeData.allowReorder},
  35.                                         grouping: #{javascript:compositeData.grouping},
  36.                           groupingView : {
  37.                              groupField : #{javascript:compositeData.groupField},
  38.                              groupDataSorted : true,
  39.                              groupColumnShow : #{javascript:compositeData.showGroupCol}
  40.                           }
  41.         });
  42.         if (#{javascript:compositeData.showFilterToolbar} == true){
  43.                 jQuery("#listxGrid").filterToolbar({stringResult: false, defaultSearch: 'cn', searchOnEnter: false});
  44.                 $("#listxGrid")[0].toggleToolbar();
  45.         }
  46.         jQuery("#listxGrid").jqGrid('navGrid','#pagerxGrid',{edit:false, add:false, del:false},
  47.                 {}, // default settings for edit
  48.                    {}, // default settings for add
  49.                    {}, // delete
  50.                    {closeOnEscape: true, multipleSearch: true, closeAfterSearch: true, showQuery: true, refreshstate:'current'} // search options                  
  51.            );
  52.            if (#{javascript:compositeData.showFilterToolbar} == true){
  53.                 jQuery("#listxGrid").filterToolbar({stringResult: false, defaultSearch: 'cn', searchOnEnter: false});
  54.                 jQuery("#listxGrid").jqGrid('navButtonAdd', "#pagerxGrid",{
  55.                            caption: "",
  56.                            title: "Toggle Search Bar",
  57.                            buttonicon: 'ui-icon-pin-s',
  58.                       onClickButton: function () {
  59.                               $("#listxGrid")[0].toggleToolbar()
  60.                       }
  61.               });
  62.         }
  63.            jQuery("#listxGrid").jqGrid('navButtonAdd','#pagerxGrid',{
  64.                    caption: "",
  65.                    title: "Reorder Columns",
  66.                    onClickButton : function (){
  67.                            jQuery("#listxGrid").jqGrid('columnChooser');
  68.                    }
  69.            });
  70.         function editLinkFmatter(cellvalue, options, rowObject) {
  71.              return "<a target='#{javascript:compositeData.target}' href='./#{javascript:compositeData.xpName}?documentId=" + rowObject["@unid"] +
  72.                              "&action=#{javascript:compositeData.action}' class='doclink'>" + cellvalue + "</a>";
  73.         }
  74.         var myid = $("[id$=cbGroupingOptions]");
  75.         jQuery(myid).change(function(){
  76.                 var vl = $(this).val();
  77.                 if(vl) {
  78.                         if(vl == "clear") {
  79. jQuery("#listxGrid").jqGrid('groupingRemove',true);
  80.                         } else {
  81. jQuery("#listxGrid").jqGrid('groupingGroupBy',vl);
  82.                         }
  83.                  }
  84.          });
  85. });
复制代码
请比较一下这段代码和上面的jqGridDemo站点的代码的区别,不是太大吧?而且不管你是不是有jQuery的基础,甚至是否使用过jqGrid,我相信你都能看出来实际上xGrid的这个地方就是jqGrid代码,只不过比如url的这行代码中,jqGrid的Demo例子是:
  1. url:'server.php?q=2',
复制代码
而xGrid是:
  1. url:'#{javascript:compositeData.url}',
复制代码

好了,到目前为止出现了3个关键知识点,我们来总结说明一下,然后再继续,首先是上一节提到的compositeData,如果你回忆不起来的话,请参考上一节最后那部分的内容:http://www.lotuschina.net/club/thread-3058-1-1.html对于XPages的学习而言,没有搞明白CC的Custom Proerties和compositeData,那真的是连门都没入!第二个知识点是Output script,先说说它的作用吧,它其实就类似于在html中写了一个内置javascript,只不过Output script是XPages的内置javascript,XPages会自动将Output script中的value值内容视作内置javascript,因此你可以在Output script中书写客户端的Javascript,一般我们在XPages的开发中,将服务器端Javascript成为SSJS,而将客户端Javascript称为CSJS,请记住Output script中书写的CSJS,不是SSJS,这也是为什么我们可以直接将jqGrid的代码直接放到XPages(或者说是放到ccxGrid这个控件中来了);那么接下来的问题就是,右边的控件里没有Output script元素,我如何在CC或XPages里增加一个Output script呢?我们切换到Source模式下,看一眼就明白了,我们在手工添加了这个标签后,XPages会自动解析为Output script,正如我在介绍XPages时提到的,XPages基于JSF技术,是IBM在JSF基础上做的扩展标签,而XPages Extension Library是xe,另外还有xc,大家以后也会遇到。

第三个知识点应该有一些同学已经意识到了,既然是CSJS,那compositeData这个SSJS的对象是如何成功被使用的?我们再一次比较一下Demo的代码和xGrid的代码的区别:
  1. url:'server.php?q=2',
复制代码
  1. url:'#{javascript:compositeData.url}',
复制代码
这是一个非常用的技巧,它使得你可以在CSJS中调用SSJS,compositeData.url是货真价实的SSJS,但当我们在CSJS中先用#{javascript:}声明后,compositeData.url就可以被XPages成功理解了!这个技术不是Victor发明的,我最先学习到这个技术的是在John Mackey的博客上:http://www.jmackey.net/groupwareinc/johnblog/johnblog.nsf/d6plinks/GROC-7GLFZG,所以暂且可以认为是John Mackey发明者中用法,大家也可以好好看看John Mackey的Blog,他是XPages的大神之一。从CSJS中调用SSJS是XPages开发必须会的一个好用技巧啊,一定要把这篇Blog看完后好好消化一下!

好了,三个知识点我们都理解完了,那接下来,我们切换到Source模式下看一眼ccxGrid的完整代码。就如你看到的那样,除去Output script部分,整个CC中的代码量很小(出去开头结尾,只剩下JS和CSS的引入,以及一个简单的布局了),因此核心的内容就是Output script中的内容,而前面我们也提到了Output script中的代码基本就是根据标准的jqGrid代码写的,而唯一要注意的就是,千万不要把值写死,而是应该尽可能统统转换为compositeData.xxx,然后在ccxGrid中定义xxx为Property Definition!这样一个高度可重用的CC就产生了!对,Victor说的是一个高度可重用的CC,而不仅仅是xGrid哦,从xGrid这个例子中,我们可以发现,所有jQuery插架都可以被转换为类似于xGrid这样的CC,实际上所有的dojo插件,ext插件,一切一切基于JS实现的插件都可以被我们CC化掉,然后我们就可以在自己的实际业务中使用,这是Victor向大家强烈推荐的将XPages技术和Web开发技术相结合的最佳模式,再比如前几天论坛上就有一个朋友问我在XPages上如何用div画一个对话框,然后如何呼出,然后如何绑定事件等等...Victor没有其他的意思,但是XPages的开发不应该是这个思路,因为你很难做出一个产品级别的对话框功能来,更别说像xGrid这样利用CC来模块化了,但实际上jQuery也好,dojo也好,其他框架也好都与非常好用的对话框功能,XPages的开发思路应该是如何在这些对话框中选取一个最好的,然后利用CC模块化之!比如我就推荐jQuery的Boxy,大家可以google一下之后,试试自己能不能把它CC化掉,有了这个对话框,你的XPages应用可以说又上了一个台阶。

好了,这节已经向大家介绍说明了xGrid是如何基于jqGrid设计出来的,并且结合内容介绍了Output script以及CSJS中调用SSJS这两个技术点,而最重要的实际上是Victor把自己开发XPages应用的开发思路推荐给了大家,Custom Control的存在使得我们可以讲一个东西模块化,因此XPages开发的思路和以前的传统开发思路会有较大的不同,我们不应该再自己造很多不能模块化的代码,而应该利用好CC的特性来选取成熟的控件,甚至是产品来进行CC化(不过要注意版权哦,万一侵权了Victor可不负责),当然,如果你们有足够的人力物力保证自主能实现一个产品级别的CC的话,可以完全鄙视并忽略Victor的这种思路。看起来xGrid的介绍已经要结束了,但其实还有一个更重头的内容没有引出,NSF中的数据是如何被传递给了我们的ccxGrid?我们在这节中多次提到了一行代码:
  1. url:'#{javascript:compositeData.url}',
复制代码
而在xGrid的Demo库中,我们会发现ContactsSSJS.xsp的配置中,这个url是指向了另一个.xsp,事实上就是这个.xsp负责将NSF的数据返回给了ccxGrid,那么这个.xsp是如何完成了这项工作呢?请关注我们的下一节会介绍的更加精彩的内容,同时也是本系列实战中,可能最有价值的一节内容:【实战】xGird,来自jQuery的神器(三):JSON、REST和XAgent
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了python应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值