求知若饥,虚心若愚。
如果按照以前传统前端的方式去架构的话,随着前端业务逻辑的增多,开发和维护会变得越来越困难,请看:
这是我去年做的华为项目Telkomsel Moovigo的目录,主要业务逻辑的代码有65个之多(每个包含page、fss、js),虽然页面、样式、逻辑代码确实是分开的,但是都是合在同一个文件里面。
去年做的另一个华为项目Digicel也是同样:
做这些项目的团队,就我们前端人员每个团队都有10人左右,维护相对简单,一人搞定6~7个就OK,那么问题来了,假如1人来搞定所有呢?因为是外包,所以这样做没太大问题,只要控制了成本,在时间少的情况下做出来且赚钱就行。有些创业公司是自主研发做产品的,如果还是这样做,会出现什么问题呢?
请看,这是我现在负责重构的微信端产品代码目录:
卧槽,这么简单,这么清爽,完全没问题呀?
这样分的好处确实有,html文件夹里面就是界面,css文件夹里面就是样式,js文件夹里面就是业务逻辑,“结构”看起来特别清晰。
但是当你打开后,近100个html、js、css文件都在各自的同一个文件夹里面,请看:
这样写最主要的两个问题是:
可能有些人不理解难复用的意思,复用怎么困难了?不是有现成的代码吗,复制粘贴重新创建一个改一改不就行了吗?这就是复用了呀!非也。
复用的意思是在不改变现有代码的基础上,依赖以前写好的代码,进行二次开发。在程序的世界,有句话一直很经典:“不要重复造轮子”。举个例,如果将每个页面看成是一辆汽车,一辆汽车由轮胎,中控,发动机等构成,且可以自由组装。同理,前端页面可以抽成很多组件,每个页面都是由这些组件组装而成。
维护的意思是需要在已上线的产品上新增业务;或者去改动有相同业务的页面。不管是修改页面上的图片、样式、位置、业务、Bug、性能都算维护。如果重复造轮子的页面越来越多,维护改动的地方就越多,到最后会越来越麻烦,改动一处,动则n处。为了解决这些问题,最好的方式就是实现组件化.
从三层架构说起,一个完整应用可以分成持久层、业务层、表现层三部分。
持久层即根据业务实现表及其映射关系,完善数据的CRUD功能;
业务层即根据业务实现对应的接口,调用持久层的东西为每个页面需要掉什么接口,返回什么数据进行封装;
表现层即根据业务实现相应的交互页面,调用业务层的东西实现数据的展现及CRUD。
三层架构各自其责,其实最痛苦的莫过于表现层。因为持久层和业务层的最终实现在表现层。
表现层是最重要的环节,做前端就是做交互,因为产品好坏的决定因素是用户的交互体验,当然其他两层也同样重要,因为表现层依赖于它们。
表现层说简单点就是做页面,三个字说起来容易,实际却不易,因为做一个页面,要做它的交互、数据展现、性能优化,还要理解页面与页面之间的关系等。页面多了,重复做这些事情就很麻烦。
为了更好的说明表现层,于是乎表现层出现了MVC架构,MVC是三个单词的首字母缩写,它们是Model(模型)、View(视图)和Controller(控制)。
刚入行web前端的人员可能是这样理解的,HTML就是Model,CSS就是View,JS就是Controller。
因为他们想的:
模型层就是指结构,HTML语义化就是在说结构呢;
视图层就是指展现效果,CSS样式就是给HTML标签实现效果呢,
控制层就是指操作,JS就是操作HTML、CSS、调用接口。
如果这样理解就大错特错啦,这里有通过 JavaScript实现的一个基础MVC模型,请注意的是:MVC 不是一种技术,仅是一种理念。
1 | /** 模拟Model,View,Controller */ |
又说多了,现在来讲什么是MVVM?
但是要讲清楚它之前,就必须讲MVC,因为根据它衍生出了MVP(这里不做讲解)和MVVM架构。
所以MVVM是MVC的衍生物,也是一种架构。
那么,MVC、MVVM两者的区别是什么呢?
依据一个简单的实例来讲解:
实现这个页面,一般思路是:
1.掉接口获取数据 2.在回调里使用获取的值渲染页面 3.添加事件
1 | var PageView={ |
在该代码中,模型(Model)就是从接口返回的record;视图(View)就是将获取的record设值到页面的render方法;控制(Controller)就是根据业务调取接口去获取数据的fetch方法。
执行的顺序是Model -> View -> Controller。
再举个稍复杂点例子,如图:
1.进入发起页面
2.添加数据
3.跳转成功发布的页面
当用户打开发起页面添加数据,点提交跳转到成功发布的页面,这一过程的顺序就是View -> Controller -> Model -> View。用户看到发起的页面是View,点提交这一步骤是Controller、提交完成数据保存到数据库是Model,从发起页面跳转到成功发布的页面是View。
1 | submit: function(el) { |
上面的问题在于:
1.用户点击发布时,提交表单前需要挨个获取DOM的val值(标注e的),这样写的坏处就是重复去获取不同DOM,重复去设值。
2.当用户提交后跳转到成功发布的页面,这样写的坏处就是跳转后需要重新加载该页面的所有资源(html、css、js、图片等),还需要调很多接口获取数据,等数据获取后又要重复去获取DOM,然后根据业务改变其样式,展示出最终的页面效果。
MVC流程图:
MVC特点:所有通信都是单向的
同样的页面用MVVM来实现,该是怎样的呢?从简单的实例入手,这里我使用了Vue.js,代码如下:
HTML代码:
1 | <div id="main"> |
JavaScript代码:
1 | var vm = new Vue({ |
在该代码中,模型(Model)就是vm实例对象的data里的值,如:user;视图(View)就是上面整个Html代码,如:;ViewModel就是vm实例对象,它建立了模型和视图的桥梁。
通过ViewModel能实现View和Model的实时更新,这样写的好处在于:
1.解决不需要重复去获取DOM、重复去操作DOM等事情,关注点能重点放在业务及页面组成上
2.方便组件化即复用
3.接口返回的数据是什么,前端马上展示什么,你变我也变
MVVM流程图:
MVVM特点:实现数据和视图的双向绑定
Vue.js的作者为**Evan You,任职于Google Creative Lab,虽然Vue是一个个人项目,但在发展前景上个人认为绝不输于Google的AngularJs,不要小看一个个人项目,比如一个人创建了backbone.js、underscore.js、coffeescript的前端大神Jeremy Ashkenas**,我们在使用其框架的时候还不是风生水起。
引用Vue的官网(**http://cn.vuejs.org/**)所介绍的那样,其主要特点有两个:
Vue.js的目标是通过尽可能简单的API实现响应的数据绑定和组合的视图组件。
Vue.js的核心是一个响应的数据绑定系统,它让数据与DOM保持同步非常简单。
在使用jQuery/Zepto.js手工操作DOM时,我们的代码常常是命令式的、重复的与易错的。
Vue.js拥抱数据驱动的视图概念。
通俗地讲,它意味着我们在普通的HTML模板中使用特殊的语法将DOM“绑定”到底层数据。一旦创建了绑定,DOM将与数据保持同步。每当修改了数据,DOM便相应地更新。这样我们应用中的逻辑就都是直接修改数据,不必与DOM更新搅在一起。这让我们的代码更容易撰写、理解与维护。
实例1:
html代码:
1 | <!-- 这是我们的 View --> |
js代码:
1 | // 这是我们的 Model |
效果:
1 | Hello Vue.js! |
看起来这跟单单渲染一个模板非常类似,但是Vue.js在背后做了大量工作。并且DOM会自动响应数据的变化。我们如何知道?打开你的浏览器的控制台,修改exampleData.name,你将看到上例相应地更新。
总结一下就是使用Vue.js我们不需要撰写任何DOM操作代码:被绑定增强的HTML模板是底层数据状态的声明式的映射,数据不过是存在了普通的JavaScript对象里。我们的视图完全由数据驱动。
实例2:
html代码:
1 | <div id="example-2"> |
js代码:
1 | var exampleVM2 = new Vue({ |
效果:
1 | Hello! |
这里我们遇到新东西。你看到的 v-if 特性被称为指令。指令带有前缀 v-,以指示它们是 Vue.js 提供的特殊特性。并且如你所想象的,它们会对绑定的目标元素添加响应式的特殊行为。继续在控制台设置 exampleVM2.greeting 为 false,你会发现 “Hello!” 消失了。
第二个例子演示了我们不仅可以绑定DOM文本到数据,也可以绑定DOM结构到数据。而且,Vue.js也提供一个强大的过渡效果系统,可以在Vue插入/删除元素时自动实现过渡效果。
也有一些其它指令,每个都有特殊的功能。例如v-for指令用于显示数组元素,v-bind指令用于绑定HTML特性。更多内容可以去官网查看API。
组件系统是Vue.js另一个重要概念,因为它提供了一种抽象,让我们可以用独立可复用的小组件来构建大型应用。如果我们考虑到这点,几乎任意类型的应用的界面都可以抽象为一个组件树:
实际上,一个典型的用Vue.js构建的大型应用将形成一个组件树。后续将详述组件,不过这里有一个假想的例子,看看使用了组件的应用模板是什么样的:
html代码:
1 | <div id="app"> |
你可能已经注意到Vue.js组件非常类似于自定义元素——它是Web组件规范的一部分。实际上Vue.js的组件语法参考了该规范。例如Vue组件实现了Slot API与is特性。但是,有几个关键的不同:
组件系统是用Vue.js构建大型应用的基础。另外,Vue.js生态系统也提供了高级工具与多种支持库,它们和Vue.js一起构成了一个更加“框架”性的系统。
最近还在继续深入学习Vue.js,最后想说:
个人认为前端的一些技术都是融会贯通的,学习一门语言或者框架本身并不是为了学习它的技术,最重要的是学习它的思维,只有思维层面得到了延伸,学习其他技术的时候才会得心应手。Vue带给我们的是前端一种解决问题的新的思维。
一句话概括:
现阶段前端人员最大的问题不是技术实现,而是思维转变。