想必教程大家已经看过,也动手做过一些Demo。倘若让大家用一句话概括’“vue是什么”,你的答案会是什么?。这里Vue官方教程也给出了自己的一句话解释。就是教程开头的第一句话
Vue.js(读音 /vjuː/,类似于 view) 是一套构建用户界面的渐进式框架。
这句话你可能并不陌生,但你未必真正读懂了它。 我们注意到这句话中有一个被作者高亮的词语—渐进式框架,其实明白了这个词语的意思,也便读懂了这句话,从而也就理解了Vue的核心理念。
那么渐进式框架究竟是什么意思,在解释这个词语之前,我们有必要先搞明白一个问题 “什么是框架?”[1]
在最初前端开发中,为了完成某个任务,我们首先利用JS从HTML文件中获取DOM元素,随后添加事件,最后进行一系列的JS编程操作。我们姑且把这种开发方式称为“DOM流”吧,“DOM流”的开发方式看起来似乎很简单实用,但是随着业务需求不断变动,你的麻烦就来了,整个代码会变得越来越混乱,无法维护。举个例子,假设现在有一个这样的需求,有一张图片,在被点击时,可以记录下被点击的次数。 这看起来很简单吧, 按照上面提到到开发方式,应该很快就可以搞定。 那么接下来,需求稍微发生了点变动, 要求有两张图片,分别被点击时,可以记录下各自的点击次数。这次似乎也很简单,只需把原先的代码复制粘贴一份就可以了。 那么当这个需求变成五张图片时,你会怎么做? 还是简单复制粘贴吧,这样完全可以完成这个需求,但是你会觉得很别扭,因为你的代码此时变得很臃肿,存在很多重复的过程,但是似乎还在你的忍受范围内。这时候需求又发生了微小的变动,还是五张照片分别记录被点击次数,不过这样单独罗列五张图片似乎太占空间,现在只需要存在一个图片的位置,通过选择按钮来切换被点击的图片。 这时候你可能会奔溃掉,因为要完成这个看似微小的改动,你原先写的大部分代码可能都需要被删掉,甚至是完全清空掉,从零开始写起,更让人郁闷的是,即使耐着性子重新写好了这个需求,一旦又来了新的需求,可能又要重新开始了。这还仅仅是一个单纯的记录点击次数的任务,“DOM流”的开发方式似乎已经出现很大的问题,而在现实的开发中,复杂的业务逻辑和巨大的代码量,更是“DOM流”根本无法承受的。
为了应对以上问题,开发人员重新梳理了代码的组织结构,把JS代码划分为三个板块,数据(M)、视图(V)、 逻辑控制(*)。 数据板块只含有数据内容,视图板块只负责更改样式,逻辑控制负责联系视图板块和数据板块和相应的逻辑,如下图所示。 这样代码结构组织的好处是显而易见的,当需求发生变动时,只需要改动相应的板块即可。还是拿上文中提到的记录图片点击次数的需求为例,这是重新组织后的代码 demo,可以看到这次代码变得清晰易懂,而且你自己也可以去设想再增加某些需求,来看看需要改动代码的程度。
其实这种开发方式,就是我们常说的MV*模式,而MVC、MVVM、 MVP[2]等都是MV*的衍生物, 其实叫什么模式名称并不重要,当你现在搞清楚了这种代码组织结构的目的,就会明白这些模式本质上都是一回事,让数据与视图间不会发生直接联系。 其实说到这里,你应该知道“DOM流存在缺陷的原因,在“DOM流”中其实是把dom当做Model,我们直接从dom中获取数据,随后又改变dom来更新视图,视图和模型其实是混在一起了,代码组织自然很混乱,不易维护。
而这种MV*的代码组织方式,渐渐的就演变成了所谓的框架。 团队开发中会选择使用框架的一个重要的原因,因为框架提前设定好的代码的组织结构让实际开发项目的代码有一个相对明确地方,这样不用担心因为团队中某个人疏忽或特有编码习惯, 造成代码整体的混乱。这里说句题外话,依照现在对框架的认识,严格来说Bootstrap并不是一个框架,其实只是一个CSS工具集,主要用来做界面美化。而Jquery也并不涉及代码的结构组织,只是把一些重复的操作进行简化 (如 DOM操作 Ajax操作等),再加上对于兼容性的解决,所以只是用来方便操作的JS库。
现在利用MV*的代码组织方式,我们拥有了可以应对需求变化的健壮代码。在使用过程中,开发人员逐渐发现在应对有频繁数据更新的需求时,我们总在做着同样的工作—获取DOM,依照新的数据来更新视图。这些工作繁琐且重复,实质上耗费了开发人员的精力。 为了解决这个问题,基于MV*的模式的MVVM框架诞生—Knockout。它利用实例的形式,把model层内容传入到实例所谓的view model中,利用binding方法完成view model与view之间的双向绑定,view mode中数据变化时,view发生变化,反之亦然。这段对于Knockout描述可能有点抽象, 毕竟上没有上代码,但你至少知道Knockout框架能替我们完成了从数据更新后视图相应的更新就行了,如下图所示。
你可能会感叹,具有这么先进理念和功能的框架,自己怎么没用过,甚至之前没有听说过。这是因为Knockout诞生的时候超越了它的时代,还记得这段开头提到MVVM框架产生的原因吗—应对有频繁数据更新的需求,而在当时前端页面的大部分就只涉及静态展示和简单交互,不存在频繁的数据变更,使用Jquery 足矣。就这样,Knockout在当时并没有流行起来,不过这个框架现在依然存在,感兴趣的可以去看看,上手也很简单 。 直到最近几年,随着随着关于数据频繁变动的需求越来越多,人们又开始重视这种自动跟新视图的理念了。 Vue就是继承这种理念的众多框架之一。如下图所示,在具有响应式系统的Vue实例中,DOM状态只是数据状态的一个映射 即 UI=VM(State) ,当等式右边State改变了,页面展示部分UI就会发生相应改变。很多人初次上手Vue时,觉得很好用,原因就是这个。不过需要注意的是,Vue的核心定位并不是一个框架[3],设计上也没有完全遵循MVVM模式,可以看到在图中只有State和View两部分, Vue的核心功能强调的是状态到界面的映射,对于代码的结构组织并不重视, 所以单纯只使用其核心功能时,它并不是一个框架,而更像一个视图模板引擎,这也是为什么Vue开发者把其命名成读音类似于view的原因。
现在我们来看看“渐进式”的意思。上文提到,Vue的核心的功能,是一个视图模板引擎,但这不是说Vue就不能成为一个框架。如下图所示,这里包含了Vue的所有部件,在声明式渲染(视图模板引擎)的基础上,我们可以通过添加组件系统、客户端路由、大规模状态管理来构建一个完整的框架。更重要的是,这些功能相互独立,你可以在核心功能的基础上任意选用其他的部件,不一定要全部整合在一起。可以看到,所说的“渐进式”,其实就是Vue的使用方式,同时也体现了Vue的设计的理念
而对于“渐进式”的解释,我在知乎上看到了一个不错的回答,这个答案也被Vue的设计者点了赞。这个回答的角度很好,主要从与React、Angular的比较来阐述的,由于本人没怎么用过另外这两个框架,也就不妄加评述,所以仅把回答进行摘录,以供参考[4]。
在我看来,渐进式代表的含义是:主张最少。
每个框架都不可避免会有自己的一些特点,从而会对使用者有一定的要求,这些要求就是主张,主张有强有弱,它的强势程度会影响在业务开发中的使用方式。
比如说,Angular,它两个版本都是强主张的,如果你用它,必须接受以下东西:
- 必须使用它的模块机制- 必须使用它的依赖注入- 必须使用它的特殊形式定义组件(这一点每个视图框架都有,难以避免)所以Angular是带有比较强的排它性的,如果你的应用不是从头开始,而是要不断考虑是否跟其他东西集成,这些主张会带来一些困扰。
比如React,它也有一定程度的主张,它的主张主要是函数式编程的理念,比如说,你需要知道什么是副作用,什么是纯函数,如何隔离副作用。它的侵入性看似没有Angular那么强,主要因为它是软性侵入。
Vue可能有些方面是不如React,不如Angular,但它是渐进的,没有强主张,你可以在原有大系统的上面,把一两个组件改用它实现,当jQuery用;也可以整个用它全家桶开发,当Angular用;还可以用它的视图,搭配你自己设计的整个下层用。你可以在底层数据逻辑的地方用OO和设计模式的那套理念,也可以函数式,都可以,它只是个轻量视图而已,只做了自己该做的事,没有做不该做的事,仅此而已。
渐进式的含义,我的理解是:没有多做职责之外的事。
好了,到这里已经解释完了“渐进式框架”的意思,现在让我们再回过头来看看开头那句话。
Vue.js(读音 /vjuː/,类似于 view) 是一套构建用户界面的渐进式框架。
是不是对Vue有了不一样的感觉,现在也应该知道如何去学习和使用Vue了吧。在学习中,我们没必要一上来就搞懂Vue的每一个部件和功能,先从核心功能开始学习,逐渐扩展。 同时,在使用中,我们也没有必要把全部件能都拿出来,需要什么用什么就是了,而且也可以把Vue很方便的与其它已有项目或框架相结合。
[1] JavaScript 设计模式设计模式-udacity
[2] [MVC,MVP 和 MVVM的图示 - 阮一峰
[3] Vue 2.0,渐进式前端解决方案-尤雨溪
[4] Vue2.0 中,“渐进式框架”和“自底向上增量开发的设计”这两个概念是什么?-徐飞