上半年成功在公司推动了由Richfaces迁移到Primefaces,后续的目标是推动引入一个客户端MVVM框架,本来相中了国货Avalon.js,可惜没有官方的英文网站和文档,最终被某JCEA(嗯,Java架构师……)否决了,好在其对引入MVVM本身倒不太反对,于是改成了Knockout.js。目前在几个前端能力较强的同事中成功局部运用起来了。但要在Java Web Team里推广,就得考虑与Primefaces整合的问题。在此想把探索整合方案的过程记录一下。最近老二刚满月,空余时间较少,希望能坚持下去不要太监吧。
先谈谈为什么要考虑JSF与客户端MVVM整合。整合的原始需求,就由此而来。
初看上去,客户端MVVM与JSF的功能是重叠的,客户端MVVM的目的是把展现逻辑移到前端来,而JSF的给人的感觉恰恰是要通过服务器端组件隐藏客户端代码,岂不是打起架来了。然而在实践中我发现,要想用JSF完全屏蔽掉JS,是不可能的。业务需求千变万化,一套现成的组件库不可能满足所有的场景。虽然自JSF2以来,开发组件的难度越来越小,但毕竟还没到信手沾来的地步。写组件为了能复用,总要额外开个组件库项目吧。如果整个团队事无大小都把涉及JS的代码封成组件往里丢,一来导致一些简单的耦合代码被强行拆分在两个包中;二来必然导致组件库过度膨胀,过度膨胀的后果就是使用者发现与其去查找是否有某个适用的组件还不如自己现写一个丢进去,结果进一步加剧组件库膨胀,恶性循环。
既然无法避免JS,让Java程序员去写少量(相对于Java和Xhtml的代码量来说)JS最容易遇到的问题是:代码零零碎碎的嵌入页面,完全没有组织,这就是我们公司的现状。原因也很直接很简单,当前主流JSF框架的Ajax实现都是基于局部渲染,替换DOM树的。为了保证在DOM树被局部替换后,手工写的JS监听器能重新绑上去,这部分绑定代码(通常也就十几行以下)就必须放到局部渲染区域内部,与被绑定的元素靠在一起。因此把所有JS代码都集中到整个页面之前或之后是不可行的。这是问题的根源,由此会引出多种影响开发与维护效率的问题,比如命名空间混乱,难以从出问题的元素反查到绑定代码,缺乏成体系的客户端API,等等。
特别是“难以从元素反查代码“这个问题,给我们维护代码带来非常多的麻烦。前面说到,为了迁就局部渲染,手写的JS代码倾向于靠近其需要操作的HTML元素。但现实中经常有这样的场景,A,B两个区域,在代码中相隔很远,由于facelet模板允许自由嵌套,往往甚至在不同目录的不同文件中,但它们逻辑上是相关的,总是被同时渲染,而且JS代码所需要的上下文状态需要在B渲染后才能决定。这种情况下我们就很容易会决定把操作A的JS代码与操作B的代码放在一起。有时它们本来就属于同一个逻辑,拆开反而更难处理。然后有一天,A出了问题,你用firebug定位到了A元素的某个属性被错误改变了,然后你就发现,根本没有任何有效线索让你快速找到B处的代码(因为JSF生成的clientId过于繁琐,程序员们往往通过css class或父子兄弟关系来做选择器,你无法确定该如何进行全局查找)。
当然还有其他一些潜在问题,比如说JSF的局部渲染往往产生大量html代码,在流量敏感的移动应用中就不容忽视了。虽然我们公司产品尚未承诺全面支持移动平台,但可以预见这个趋势是无法避免的。
那么从另一个角度看,为何不干脆全面改成RESTful加客户端MVVM。这主要在于JSF在安全性和权限处理上有绝大便利和优势。只要一个组件的rendered属性为false,它内部的command组件就绝对不会被执行。只要一个input组件的readonly为true,它的值就绝对不会被更新到模型中去。只要f:selectItems中不存在某个选项,它依附的select组件就不能对这个选项的值进行decode,自然也无法更新到模型中。换而言之,非常自然地避免了恶意请求的侵袭。不使用JSF的话,我们就要在安全性和权限检查上耗费不少精力。更何况,在大部分场景下,使用现成的组件库是非常方便的。
由此可以总结出这次整合的需求:
1. 解决JS代码碎片化,命名空间混乱的问题
2. 解决难以从元素反查JS代码的问题
3. 提供相对组织良好的客户端API
4. 减少局部渲染响应流量
5. 保留JSF的提交方式,确保服务器的权限检查能正确执行
6. 确保原有的JSF组件能无缝正常使用
然后谈谈客户端MVVM(或MVC)框架的选择。
首先需要大量JS代码来建立模型的Backbone.js可以出局了,公司里的Java程序员不可能愿意手写大量额外JS代码,毕竟我们已经有了完善的服务器端数据模型,客户端模型属于锦上添花,不能喧宾夺主了。
其次使用静态模板的Ember.js和React.js也可以离场了,静态模板难以与JSF组件整合。况且先写模板再引用的方式也不符合原本的开发习惯。
本来Angular.js给我眼前一亮的感觉,但使用下来(用其做了几个内部项目和一个facebook应用)发现,体系太封闭了。一旦让Angular.js接管了,想绕过它进行局部渲染,甚至仅仅是使用JSF的正常方式提交(而不使用它自带的提交功能)后要更新模型值都极其繁琐。两个ViewModel之间通信只能走Observer模式,对Java程序员们来说代码量太大。据说性能一般(建议同页面不超过2000个绑定),而且自带了我感觉根本无法推广的包依赖功能。只好忍痛割爱了。
然后顺着Angular.js,又找到了”到哪儿网“的Avalon.js。这个框架老实说做的不错,借鉴了Angular.js与Knockout.js的不少优秀特性。我用它来做了一些内部项目,甚至局部用到了生产环境的一些次要功能上,都很顺手而且基本没有出什么问题。但最大问题是,这东西没有英文网站和文档。要在团队里推,跟项目经理一谈就被否决了:”你先教会我普通话再说……“。
另外,这个项目的版本概念也比较模糊,没有开发版与稳定版之分,主干上一边改Bug,一边加新特性,等你报的bug改好了,一但更新版本,没准新增的特性又出bug了,没个尽头。但总的来说,这个项目还是不错,一些个人项目或内部项目我还是倾向于使用。
最后,Avalon不能用,就只能退而求其次,改用Knockout.js了。Knockout.js的原生版本基本上实现了Avalon 80%的特性 (或者说,Avalon借鉴了Knockout后又添加了20%的新特性)。但其扩展性感觉要比Avalon好一点,自定义binding非常方便,所以我又只好通过自定binding把这20%的特性加回去。但Knockout.js对ViewModel嵌套的支持很弱,这点暂时无解,好在在JSF整合中,JS模型本就力求简单,不能嵌套也问题不大。最烦人的问题是,Knockout.js在语法层面上区分模型中的普通变量和监控变量,普通变量直接访问,监控变量需要作为getter/setter函数访问,你使用时必须记住模型中的某个属性到底是什么类型,颇令人不爽(相对来说,Avalon想尽办法把所有属性都统一成直接访问了,在旧版IE浏览器甚至动用了VBScript来帮忙,使用上方便不少)。
不管如何,经过一番权衡,最后选定了Knockout.js。下一节开始整合了。
-- 本节完 --
分享到:
相关推荐
Knockout.JS是一个轻量级的JavaScript库,专门用于实现MVVM(Model-View-ViewModel)模式。MVVM模式在客户端开发中非常流行,因为它简化了数据绑定和UI更新的过程。Knockout.JS的核心功能包括数据绑定、依赖跟踪和...
Knockout.js是一个非常流行的JavaScript库,它遵循MVVM(模型-视图-视图模型)设计模式,主要被用来帮助开发者实现JavaScript应用程序中丰富的用户界面。在本文中,我们将详细介绍Knockout.js的核心概念以及如何在...
Knockout.JS是一款强大的JavaScript库,它提供了数据绑定和依赖跟踪功能,使得在浏览器端创建复杂的用户界面变得更加简单。而ASP.NET MVC是一个流行的服务器端框架,用于构建动态、数据驱动的Web应用。 首先,了解...
Knockout.JS 是一个JavaScript库,专门用于实现MVVM(Model-View-ViewModel)模式,简化了前端数据绑定和动态用户界面的创建。在ASP.NET MVC 4项目中,Knockout.JS可以无缝集成,帮助开发者实现在客户端实时更新视图...
1. `src/`目录:存放knockout.mapping插件的源代码,通常包括JavaScript文件,如`knockout.mapping.js`或`knockout.mapping.debug.js`,供开发者查看和调试。 2. `dist/`目录:包含已编译和压缩的版本,适合在生产...
1. **视图模型(ViewModel)**:在Knockout.js中,ViewModel是连接模型和视图的桥梁。开发者可以定义ViewModel对象,包含模型数据和业务逻辑,然后在视图中通过数据绑定来引用这些属性和方法。 2. **数据绑定**:...
《ASP.NET MVC 5 with Bootstrap and Knockout.js》是由O'Reilly出版社于2015年出版的一本专业书籍,主要面向的是希望掌握ASP.NET MVC 5开发技术,并结合Bootstrap和Knockout.js构建现代Web应用程序的开发者。...
### Knockout.js Succinctly:全面解析与应用实践 #### 一、Knockout.js简介与特点 **Knockout.js**是一款轻量级的客户端MVC(Model-View-Controller)框架,专为简化现代Web应用程序开发而设计。其核心功能之一是...
Beginning with a vital overview of Knockout.js, including the MVVM design pattern, you will create a simple but powerful application capable of integrating with ASP.NET MVC as well as gain a thorough ...
基于 BOOTSTRAP 和 KNOCKOUT.JS 的 ASP.NET MVC 开发实战。 利用动态服务端Web内容和响应Web设计共同构建的网站,在任何分辨率、桌面或移动设备下都可以进行良好的显示。通过本书的实践应用,你将可以学习对ASP.NET ...
With this practical book, you’ll learn how by combining the ASP.NET MVC server-side language, the Bootstrap front-end framework, and Knockout.js—the JavaScript implementation of the Model-View-...
简单的knockout.js/websockets/node.js实时游戏 这是一个非常简单的实时游戏,使用 node.js、knockout.js 和 socket.io 创建。 ##目标 尝试比其他玩家更快地解决简单的数学方程。 每场比赛都有时间限制(默认...
Knockout.JS is an emerging JavaScript presentation framework that promotes a solid solution design in combination with Jasmine, a well-known unit testing library. They both ensure rapid development ...
JavaScript捆绑与最小化 小结 第14章构建数据模型 Code—First模型 定义DbContext并初始化数据 视图模型 小结 第15章布局实现 共享布局 购物车摘要 分类菜单 小结 第16章图书列表 主页 特色图书 按...
KnockOut抠图插件,支持32、64位版系统(与photoshop位数无关) 目前测试使用win10(64位)、photoshop cs6 13.0(32位) 1.下载后放在photoshop安装目录中的Plug-ins中(解压后Plug-ins文件夹中应该会包含:KnockOut.8bf...
**Knockout.js与jQuery Mobile的整合:使用Shim** 在Web开发中,Knockout.js和jQuery Mobile是两个非常流行的库,分别用于数据绑定和移动应用的UI交互。它们结合使用可以创建出功能强大且用户友好的动态移动界面。...
Knockout.js能够很好地与其他JavaScript库和框架协同工作,例如可以轻松地将Bootstrap或其他UI框架的组件与Knockout.js的绑定相结合。 #### 更改button的状态 通过绑定`disabled`属性,可以基于数据条件动态地启用...