angularjs的编程思想
2015年4月份的时候,接触过几天angularjs,但是那时候并不理解它。
在开始使用时,看到它的自定义标签,自定义属性,连src都要改写为ng-src,觉得很不标准,太hack味道了,有点像奇技淫巧,与html标准冲突,不能成为完美的解决方案。
万一用久了连哪个是标准html哪个是angular标签都搞不清了那不是亏大了?
的确,angular不可避免要出现这些问题。因为html标准压根就没有提供自定义标签的功能。angular做了标准html能力之外的事情,必定要加入非标准的元素。
而且,它反对使用jquery。求教同事,同事说喜欢angular的数据双向绑定,但是我觉得如果只要双向绑定,用jquery也可以实现啊,干嘛还要搞这么多概念,又是模块又是服务又是服务提供者又是工厂的。
之后,我找了一份新工作,大概有5个月没有再接触它了。
在新工作中,我做了很多维护性的工作。在我维护别人的代码的时候,发现了很多问题。
js文件中写了非常多的html字符串,js代码和html模板字符串混在一起;
js文件中引用了其他js文件中的变量,这些变量不知道从哪里来;
查看html页面搞不清楚交互逻辑;
js文件和页面绑定,页面和js只能作为整体才能构成一个可执行单元,即js不能单独运行。
总结就是
js和html没有实现真正的分离,即使分开写在两个文件;
js没有实现模块化管理,没有实现依赖管理;
html无法实现数据驱动结构,即无法根据数据来动态生成html结构。
于是我开始思考,有什么办法可以解决这些问题?或者有没有已知的解决方案?
angularjs的数据双向绑定,实现了真正的视图与数据分离。
在理解其实现方式之前,有必要对其思想源头进行梳理、理解其理念。
网页展示信息,使用的是超文本标记语言html。它由标签组成,标签定义了要展示的内容的结构(结构)和内容的样式(样式)以及内容(数据)。
在最初,网页设计将数据和样式硬编码在标签中。
这样在网站的内容需要更新或者网站的风格需要切换时,就需要到原来的网页的每个标签中修改内容和样式,维护起来十分麻烦。
这是最早的静态网站技术,网站的内容不能自动更新,必须手工更新。
后来,开发者通过程序,向浏览器写html格式的字符串的方式,实现网站内容的动态化。
因为服务器写的字符串,可以通过模板字符串和数据拼接得到。这就是后来的类似servlet的技术。
然而,这样的方式,维护起来将是个灾难。所以后来将模板和数据进行分离。出现了类似jsp的技术。这是服务器端网页技术。
这时候,网页的模板,对于浏览器端来说是一个不变的模板,服务器端填充对应的数据即可。
再后来,ajax技术出现了,可以无刷新的与服务器端进行通信(获取数据)。
在js代码中(js的流行,极大的收益于ajax),通过ajax发送请求,获得数据,然后更新到页面。于是在浏览器端,页面的数据动态化了,随之页面标签结构也动态化了(有些标签是根据数据而创建的,当有数据时创建标签绑定事件。
例如一个商品列表,需要根据ajax获得的商品数组,动态创建标签显示商品。例如一个树形菜单。)。
为了获得请求参数和将数据更新页面,需要定位包含这些数据的标签。通常通过dom的api可以实现。
但这样有很大的弊端。需要手动获取页面中的数据作为请求参数,需要手动将ajax的响应数据填充到页面。
导致处理请求和响应相关的js代码(应该只负责处理数据,而不用关心数据到底在页面的什么地方)中,依赖了页面元素的id属性(或其他属性)和页面元素的结构。
angularjs的数据双向绑定,解决的就是这样的问题。
设计者需要做的事情,之前是,设计页面标签结构、样式、使用js获取页面数据作为参数发送ajax请求,将ajax响应的数据,手动更新到页面、使用js进行事件绑定等。
现在是,设计页面标签结构并将需要获取和更新的数据分别与js变量进行绑定,绑定事件、设计样式、js代码中发送ajax请求时,请求参数从特定的js变量中获取。
返回的数据写入特定的js变量即可(获取页面中的数据和将数据更新到页面的操作由框架完成)。
后者的优势,页面富有交互信息,仅阅读页面html代码即可知道页面的交互逻辑;
ajax请求参数,不用手动关联页面获取了,从特定的js变量中获取(实现了视图和数据、和数据处理的分离。
当然,标签的样式属性也是数据)。由于页面数据的动态化,导致页面标签结构的动态化,这使得在浏览器端,固定的模板已经无法满足与用户复杂的交互的需要。在浏览器端,需要像服务器端一样,根据数据动态生成html(例如jsp,编译后生成html)。即,需要一种根据数据生成html片段的方式。angularjs鼓励不要更改dom,但是部分标签结构的动态化,是ajax技术的必然结果,也是增强用户交互必须要解决的问题。当然,angularjs也是可以实现标签结构动态化的。并且动态的标签,也同样是视图与数据分离的。可以将angular和jsp类比。jsp是在服务端生成html,它生成动态网页。angular是客户端生成html,它不仅可以生成动态网页,还能够处理复杂用户交互。当页面到达浏览器时,jsp是无法根据数据再进行任何处理(事实上这时候jsp已经被处理为html,之后的动态性还得使用js)。而如果使用angularjs,则是将所有的动态性都使用js完成。也就是说,之前网页内容的动态性,是由jsp和js共同实现,angular的理念是服务器只返回最初的模板,网页内容的动态性全部由js负责。但这样会导致需要更多了请求服务器,占用更多的链接。有些数据虽然是动态的,但无需用户交互(例如商品分类,只有更新了数据库才更新页面上的商品分类。而商品列表,会根据用户查询条件动态请求。),这些动态数据在服务器端生成即可。所以,angularjs应该不太适用于高并发的网站。这里也应该确定一个方案,就是对动态数据进行分类。一类是根据数据库中的数据动态,另一类是用户交互的数据动态。前者应该用jsp技术,后者应该用ajax(例如页面中的商品分类列表、省市区县列表,这些内容在请求页面时,通过jsp构造html和填充数据。而页面中的商品列表,则不要用jsp填充,而应该在js中通过ajax获取数据后填充。这要求使用jsp而不是angular,十分不适合用前端框架。有些设计并没有考虑到这点,对于交互性的动态数据,他们也使用jsp处理,然后又不得不用js再处理一遍。这样是重复劳动,非常浪费劳动力)。不过,设计应该尽量满足拓展性,考虑到未来。如果有些非交互的动态数据,现在成为了交互性的动态数据(有这样的场景吗?),那么又该如何设计?那么原来由jsp处理,转为由js处理。考虑到这样的场景极其少,如果有,重新设计这部分数据处理即可。当然,使用jsp技术的代价是,无法实现前后端分离。为了实现前后端分离,而又不会存在很多非交互动态数据的请求,可以一次性请求所有初始化数据。
angularjs的指令,增强了html语言的描述能力。之前的方式,是硬编码描述结构,或者通过js拼接字符串描述结构。缺少一种根据数据描述结构并动态将数据填入结构的方式。例如,<li ng-repeat="item in items"><a href="{{item.url}}">{{item.name}}</a></li>。使用angular之后,html的功能增强了,这与使用jq插件不一样的是,前者提供描述动态结构能力和填入数据的能力,后者提供用字符串拼接好的模板。即,前者提供根据数据描述动态结构的功能,后者提供的是特定的动态结构。比如用前者,我们可以仅通过html就实现树形菜单。而用jq,要么使用树形菜单插件(他人已实现的特定的动态结构),要么自己用js拼字符串。就好象jsp和使用servlet输出html字符串一样,前者提供了选择、循环结构和函数,当然处于浏览器中的"jsp"能够具有用户交互动态性。当我们需要自定义组件的时候,通常需要将html结构循环或者递归(例如树形结构),使用指令可以直接通过html描述这种结构,使用jq则需要通过js循环和递归拼接字符串和数据来实现。对于理解ng,我们可以这么类比,ng对应jsp,js对应servlet。至于css,把它理解为html结构中的一部分,同样可以被ng或jsp动态化。用jq开发相当于使用servlet根据数据拼接成html字符串。
angualrjs的定位
它是一个框架,不是一个ui组件库。如果它能够提供应用中的大部分组件,那么它将会是一个非常好的解决方案。因为任何一个应用,都会包含大量的通用组件和自己的专用组件。如果它提供了通用组件,而又为自定义组件提供极好的方式,那么它将很容易成为一个流行框架。