摆脱DOM操作,从TodoMVC看angularJS

取代jQuery?

我很久之前便听说了angularJS的大名,之前的leader也经常感叹angularJS的设计如何如何精妙,可叹一直没有机会深入了解,国庆长假因为没钱出游,倒是可以对他做一个了解……

根据之前的经验,就现有的前端项目,如果最初没有良好的设计,做到一定阶段一定会变得难以维护,就算最初有设计,变化无常的PM也会让你的项目BUG丛生。

一个页面的复杂程度不断的增加,依赖模块也会变得混乱,而其中最为头疼的就是页面级随心所欲的DOM操作了!

MVC类的框架可以很好的解决以上问题,而号称MVVM的angularJS在处理这种情况似乎更有话语权,所以我们今天便来好好研究其一番。

angular适合做具有复杂数据交互的前端应用,他旨在让我们摆脱繁琐的DOM操作,而将注意力集中在业务逻辑上,这里摆脱繁琐的DOM操作是个非常关键的愿景,也是很多人不太理解,甚至会将jQuery这种库与Backbone或者angularJS这种框架做对比的原因。

这里举个jQuery不依赖MVC骨架的例子,我们的订单填写页,需要在商品数量变化后导致金额变化,并且没有选商品时,支付按钮不可点击:

对于一个有些经验的菜鸟来说,可能会这样写代码:

对于一些有一定经验的老鸟来说,可能会这样写代码:

第一段代码可能会导致你年底加薪无望,并且在团队中没有话语权;而第二段代码积累到一定量后会让这个项目变得不可维护:

① 支付工具栏初始化状态如何显示,如果数字组件按需做异步加载,这个显示将变得更加负责。

② 哪些操作将导致支付栏变化,你如何组织这些变化的代码,是让他四散到各处,还是集合在一起,集合后导致函数过大怎么办?

③ 新增的导致工具栏变化的操作会不会对原来的操作造成影响,新增的代码放在何处?

④ 如果有地方要使用工具栏处的信息,取的信息会不会是无效的(取的时候可能正在变化),应该通过DOM取还是内存取?

⑤ 如果支付栏DOM结构如果变化,对你的程序影响有多大,如何主流程的影响,比较支付点击后只需要操作数据,不需要关注DOM?

⑥ ……

这个就是仅仅依赖jQuery要面临的问题,并且这种问题是无解的,因为这里的专注点是DOM操作而不是数据,如果将关注点变成了数据,代码就不是这样写的,DOM操作仅仅是过程而不是目的,我们代码的目的,往往是展示数据、获取数据,这点一定要清晰。

所以让我们带着这些问题:angular的优势在何处,他如何改善我们的编程体验,进入今天的学习吧。

初探angularJS

Hello World

学习任何一门语言,Hello world是必不可少的,他是我们迈向精通的唯一路径:

被{{}}包裹的便是angularJS变量,上述程序稍作改变的话:

便会同步显示文本框输入内容,这里通信的基础是model对应着ng-model,只要被ng-app包裹就会受angularJS控制,用angularJS自己的话说:HTML标签增强

作用域

为什么文本框中的变化会体现在外层,这个涉及到了ng-model的双向绑定知识,我们暂时不予理睬,但是外层又是从哪里读取name这个变量的呢?

在angular中,属性会存储在一个@scope(作用域)的对象上,每次我们对文本框的更新皆会通知scope上的name属性,在angular中,scope是连接controllers(控制器)与template(视图)的主要胶合器。

上述代码完全不涉及js代码,真实的场景中每个代码段会对controller做依赖,我们这里对代码做一些更改:

这里首先定义了一个application模块,后续会看见,我们每次代码一定会新建一个application,相当于命名空间的意思,后面还可以做依赖用。

接着,我们创建了一个controller模块,这里已经有点MVC的味道了,controller接受$scope属性,这个时候模板上所有子标签对这个控制器中的属性便有了访问权限,这里用到了一些angular指令

ng-app:告诉html标签已经处于angular的控制了,可以使用angular的特性
ng-controller:一个module下面可以包括多个控制器,每一个标签所属的控制器由该指令指定

上述代码是将控制器中的数据读出来,我们同样也可以将View中的数据读入到控制器:

PS:看到这里,老夫虎躯为之一振,对该特性的实现产生了兴趣,后续值得深入

指令

指令让我们有能力使用angular规定的方式为HTML标签增加新特性,angular内置了很多有用的指令,这里仍然举一个简单的例子说明问题:

我们除了使用angular的内置指令外,还可以自定义指令,比如这里的让文本框自动获取焦点的指令:

指令的使用可以很复杂,后续我们会更加深入,这里再举一个单独使用的例子:

指令的定义有很多参数,可以指定该指令作为属性还是作为标签,这个我们后续再深入了解。

过滤器

感觉过滤器是参考的smarty的语法,一般而言是用作显示的增强,angular本身也提供了很多内置过滤器,比如:

感觉比较有用的是日期操作过滤器:

数字格式化:

当然,我们可以使用自定义过滤器,比如这里我想对超出某一区间的数字加…

具备了以上知识,我们尝试进入To都MVC看看

参考:http://www.cnblogs.com/whitewolf/p/angularjs-start.html

TodoMVC

我们由最新的TodoMVC下载代码:http://todomvc.com/,首先查看js引用情况:

除了angular本体文件外,还多了个angular的扩展,做单页应用的路由功能的,这个路由代码量不大,使用和Backbone的路由比较类似;app.js为入口文件,配置路由的地方;余下是控制器文件文件以及一个localstorage的操作服务,余下就是指令了。

代码首先定义了一个模块作为本次程序的命名空间:

ngRoute为其依赖项,可以从route的定义看出:

这里来看看其router的配置,以及index.html的写法:

这个代码现在基本看不懂,大概意思应该就是根据路由执行config中的逻辑,将模板展示在页面上,其中index.html有一段代码应该是用于替换模板的:

我们先抛开那段看不懂的,直奔主流程,目光聚焦到控制器controller:

这段代码130行不到,让我体会到了深深的神奇,首先我们在app中返回了读取到localstorage的对象:

然后就在controller的依赖项中读到了被注入的对象:

此时,模板也被插到了页面上,等待controller的执行:

首先这里有一个$watch方法,监控着todos的变化,每次变化都会体现到这里,导致view的变化:

然后我们将关注点放在新增项目上:

View上的调用点是:

首先这段代码中有一个autofocus的指令,没有什么卵用:

可以看到model直接绑定到了该文本框上,所以addTodo方法可以直接根据$scope获取文本框的属性,完了调用单例store提供的静态方法存储数据,saving参数可以暂时将文本框变成不可编辑状态,而后todo数据更新,会自动引发View变化,于是流程结束!!!

我们如果将$scope放到全局上对其数据造成变化:

每次返回操作视图时候,该变化会马上反应到View上,于是我发现了以下不同:

① 因为所有与业务相关的数据全部做了双向绑定,我根本没有必要由dom获取数据了,我自然而然的到$scope中获取数据,不知道为什么,这个特性让我有点愉悦!

② 我要做的事情其实就是约定好数据对象,然后将该对象放到要用到的所有视图上即可,每次内存中数据变化Dom会同步更新

于是通过以上两点,我似乎得到了一个惊人的结论:

因为,前端要做的事情只不过是正确的展示服务器端的数据,每次DOM事件造成的改变也往往是数据引起的,如果我们能做到数据变化自动更新到DOM变化的话,那么DOM操作的必要似乎没有了,而angular干的事情正是如此!!!

思考

到此为止,TodoMVC的代码我虽然没有完全看懂,但是他带给我的震撼是全方位的,之前使用MVC类框架可以规范数据到DOM的操作,很大程度上解除DOM和JavaScript的耦合关系,而angular似乎完全抛开了业务数据导致的DOM变化操作!!!

我们现在团队有一mis后台系统,我在考虑是否要把它接过来,使用angular+bootstrap重构,可能别有一番风味吧!

最后,今天初步调研了一下angularJS,就已经感受到他的魅力了,后面时间需要将之用于实践,并且对其设计思想作深入研究!!!

 

1 7 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部