AngularJS入门知识之MVW类框架的编程思想探讨
本文通过实现两个简单的业务需求,探讨angularjs和传统的javascript控制dom实现方式的差别,并尝试理解mvw此类框架在流行的web前端开发中的编程思想。
这个需求很常见,比如,一个两级菜单,在第一级别菜单项点击时候,对应的子菜单项目应该显示或隐藏。
jquery的实现:
<!-- html -->
<ul class="parent">
<li class="parent_item">
item 1
<ul class="child">
<li class="child_item">item child 1</li>
</ul>
</li>
</ul>
// javascript
$('li.parent_item').click(function(){
$(this).children('ul.child').toggle();
})
angularjs的实现:
<!-- html -->
<ul>
<li ng-click="hide_child = !hide_child">
item 1
<ul ng-hide="hide_child">
<li>item child 1</li>
</ul>
</li>
</ul>
传统操作dom的方式,不再赘述。angularjs的实现,相对代码要精炼很多,只有html的版本即可。以上代码,用到了angularjs这些知识点:
ng-click和ng-hide都是框架自带的directives(指令),前者相当于给li标签提供了一个event handler,在该html元素(li)被点击的时候,会执行hide_child = !hide_child这个expression(表达式)。我们先看一下ng-hide这个指令,它会根据赋值的表达式结果(布尔值)来控制该html元素是否要显示(通过css实现)。也就是说,如果hide_child这个变量如果是true,那么ul就会被隐藏,否则结果相反。
这里hide_child其实是上的一个变量,对它的值的变更,也可以用controller控制器包装一个方法来实现,只不过现在的语句比较简单,直接写在了指令的赋值里面。
通过以上简单的代码分析,我们可以看到angularjs两个比较明显的特点:
1.通过指令和表达式对dom的操作进行了封转,只需简单的代码便可省去额外的javascript代码
2.指令和表达式的应用,只直接嵌套在html中的,这和jquery推从的unobtrusive javascript的代码风格有些背道而驰
我们先看另外一个需求,再详细解释上面的结论。
需求2:通过点击div,触发选择form中的一个radio button
传统的html form元素,在如今的移动设备上,操作起来并不是十分友好。比如,radio button单选框,在触摸屏上,需要精确的位置定位,才能控制好这个组件,但是手指定位又很粗糙。常见的做法,是添加一个对应的label控件,但是文字本身占屏比例也并不理想,而且也不具备明确的信息传达效果。所以,通常会间接操作一个区域比较大的div或者li标签。
jquery的实现:
<!-- html -->
<ul>
<li class="selection">
<input type="radio"
id="option1" />
<label for="option1">option 1</label>
</li>
</ul>
// javascript
$('li.selection').click(function(){
$(this).children('input[type="radio"]').click();
})
angularjs的实现:
<!-- html -->
<ul>
<li ng-repeat="option in options"
ng-click="model.option = option.value"
ng-class="{active: model.option == option.value}" >
<input type="radio"
ng-model="model.option"
value="{{option.value}}"
id="option1" />
<label for="option1">option 1</label>
</li>
</ul>
在这个解决方案中,我们同样没有涉及到额外的javascript代码,并且多用了几个指令。为了对比参照,我们只关心ng-click和ng-model这两个指令的表达式。
我们先看一下input这个元素的ng-model指令,这里赋值的意思是,我们把模板上的input和$scope.model对象的option属性进行了关联,深入了解数据绑定可以参考data binding。这种指定关联,使得模板控件直接和数据model进行了绑定,并且这种绑定是双向的。意味着,一旦用户修改控件中的值(勾选radio input),对应的model对象就会重新赋值(model.option);同时,如果model对象的值发生了变化,模板中的input控件也会对应反映变化。而这点,在上述jquery的实现中,其实是没有做到的。
所以,这里通过angularjs的数据绑定,点击li元素间接完成触发input的流程是这样子的:
1.点击li标签,给model.option赋值;
2.修改了model对象,定位到对应input控件(value的值为model.option那个);
3.激活input控件的checked属性
通过以上两个案例,我们对web前端的操作有了新的认识。
首先,技术实现上,通过引入新的指令,表达式,数据绑定等概念,我们可以完全新的方式去操作dom,而不仅仅局限在用户和html组件交互操作上的javascript代码的实现。这种思想的变化是巨大的。
从本世纪初,动态web编程的兴起开始,服务器端的编程技术一直在改进。从一开始的cgi/php/asp,由语言和平台产生了.net vs. java,开发效率和软件过程促进了mvc框架/orm/aop等,性能和大数据带来了nodejs/nosql/hadoop等,而浏览器前端的技术需求似乎没有那么激进过。一方面,通过服务器端和数据库,大部分b/s模型的业务需求都能满足;再者,浏览器本身存在不同平台的差异性,对脚本语言和渲染技术的标准不兼容,以及运算能力的欠缺和安全性的考虑。
在这种情况下,浏览器端的需求,大部分时候只需要考虑渲染页面和简单的用户交互。html/dom加上javasript/css就这样成就了前端的主要工作。所以,以前是没有前端工作师,只需要web设计师的。慢慢对前端的要求多起来,jquery成为使用程度最高的一个javascript操作dom的封装库。而在这个阶段,jquery/javascript的主要任务,仍然只是作为面向用户浏览器终端呈现和交互的工具。
理解了jquery的起源,我们不难发现,以前追求的一些规则,譬如unobtrusive javascript,当时局限于实现的手段和方式,为了分离dom和javascript代码逻辑,我们优先选择了维护性更高的方式。前端对javascript的需求加大之后,出现了很多mvc/mvp的前端框架,以及angularjs所谓的mvw(model-view-whatever),javascript和dom一刀切的方式发生了变化。原先我们考虑界面显示和用户交互的直接操作,现在我们有了客户端的数据绑定,丰富的指令,依赖注入,等待我们的将是全新的编程模型和思维方式。
上一篇: 不是好孩子就不让上街