1. 论坛系统升级为Xenforo,欢迎大家测试!
    排除公告

vue.js 与其他前端框架详细对比

React React 和 Vue 有许多相似之处,它们都有: 使用 Virtual DOM 提供了响应式 (Reactive) 和组件化 (Composable) 的视图组件。 将注意力集中保持在核心库,而将其他功能如路由和全局状态管理交给相关的库。
By 小栗儿, 2017-09-30 | |
  1. 小栗儿

    React


    React 和 Vue 有许多相似之处,它们都有:

    • 使用 Virtual DOM
    • 提供了响应式 (Reactive) 和组件化 (Composable) 的视图组件。
    • 将注意力集中保持在核心库,而将其他功能如路由和全局状态管理交给相关的库。
    由于有着众多的相似处,我们会用更多的时间在这一块进行比较。这里我们不只保证技术内容的准确性,同时也兼顾了平衡的考量。我们需要承认 React 比 Vue 更好的地方,比如更丰富的生态系统。

    相似之处


    React与Vue存在很多相似之处,例如他们都是JavaScript的UI框架,专注于创造前端的富应用。不同于早期的JavaScript框架“功能齐全”,Reat与Vue只有框架的骨架,其他的功能如路由、状态管理等是框架分离的组件。

    Virtual DOM


    Vue.js(2.0版本)与React的其中最大一个相似之处,就是他们都使用了一种叫'Virtual DOM'的东西。所谓的Virtual DOM基本上说就是它名字的意思:虚拟DOM,DOM树的虚拟表现。它的诞生是基于这么一个概念:改变真实的DOM状态远比改变一个JavaScript对象的花销要大得多。

    简单来说,Virtual DOM是一个映射真实DOM的JavaScript对象,如果需要改变任何元素的状态,那么是先在Virtual DOM上进行改变,而不是直接改变真实的DOM。当有变化产生时,一个新的Virtual DOM对象会被创建并计算新旧Virtual DOM之间的差别。之后这些差别会应用在真实的DOM上。

    例子如下,我们可以看看下面这个列表在HTML中的代码是如何写的:
    代码:
    <ul class="list">
      <li>item 1</li>
      <li>item 2</li>
    </ul>
    
    而在JavaScript中,我们可以用对象简单地创造一个针对上面例子的映射:
    代码:
    {
       type: 'ul',
       props: {'class': 'list'},
       children: [
           { type: 'li', props: {}, children: ['item 1'] },
           { type: 'li', props: {}, children: ['item 2'] }
       ]
    }
    
    真实的Virtual DOM会比上面的例子更复杂,但它本质上是一个嵌套着数组的原生对象。当新一项被加进去这个JavaScript对象时,一个函数会计算新旧Virtual DOM之间的差异并反应在真实的DOM上。计算差异的算法是高性能框架的秘密所在,React和Vue在实现上有点不同。

    Vue宣称可以更快地计算出Virtual DOM的差异,这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。

    而对于React而言,每当应用的状态被改变时,全部子组件都会重新渲染。当然,这可以通过shouldComponentUpdate这个生命周期方法来进行控制,但Vue将此视为默认的优化。

    组件化


    React与Vue都鼓励组件化应用。这本质上说,是建议你将你的应用分拆成一个个功能明确的模块,每个模块之间可以通过合适的方式互相联系。在Vue中,如果你遵守一定的规则,你可以使用单文件组件.
    代码:
    //PastaItem.vue
    
    <template>
    <li class="pasta-dish list-unstyled">
       <div class="row">
           <div class="col-md-3">
               <img :src="this.item.image" :alt="this.item.name" />
           </div>
           <div class="col-md-9 text-left">
               <h3>{{this.item.name}}</h3>
               <p>
                   {{this.item.desc}}
               </p>
               <button v-on:click="addToOrderNew" class="btn btn-primary">Add to order</button> <mark>{{this.orders}}</mark>
           </div>
       </div>
    </li>
    </template>
    
    <script>
    
    export default {
       name: 'pasta-item',
       props: ['item'],
       data:  function(){
           return{
               orders: 0
           }
       },
       methods: {
           addToOrderNew: function(y){
               this.orders += 1;
               this.$emit('order');
           }
       }
    }
    
    </script>
    
    <style src="./Pasta.css"></style>
    
    正如上面你看到的例子中,HTML, JavaScript和CSS都写在一个文件之中,你不再需要在.vue组件文件中引入CSS。
    而在React语法中,JavaScript与JSX被写入同一个组件文件中。
    代码:
    import React from "react";
    
    class PastaItem extends React.Component {
    
       render() {
           const { details, index } = this.props;
    
           return (
               <li className="pasta-dish list-unstyled">
                   <div className="row">
                       <div className="col-md-3">
                           <img src={details.image} alt={details.name} />
                       </div>
                       <div className="col-md-9 text-left">
                           <h3>{details.name}</h3>
                           <p>
                               {details.desc}
                           </p>
                           <button onClick={() => this.props.addToOrder(index)} className="btn btn-primary">Add to order</button> <mark>{this.props.orders || 0}</mark>
                       </div>
                   </div>
               </li>
           );
       }
    }
    
    export default PastaItem;
    

    Props


    在上面两个例子中,我们可以看到React和Vue都有'props'的概念,这是properties的简写。props在组件中是一个特殊的属性,允许父组件往子组件传送数据。
    代码:
    Object.keys(this.state.pastadishes).map(key =>
       <PastaItem index={key} key={key} details={this.state.pastadishes[key]} addToOrder={this.addToOrder} orders={this.state.orders[key]} />
    )
    上面的JSX库组中,index, key, details, orders 与 addToOrder都是props,数据会被下传到子组件PastaItem中去。

    在React中,这是必须的,它依赖一个“单一数据源”作为它的“状态”。而在Vue中,props略有不同。它们一样是在组件中被定义,但Vue依赖于模板语法,你可以通过模板的循环函数更高效地展示传入的数据。
    代码:
    <pasta-item v-for="(item, key) in samplePasta" :item="item" :key="key" @order="handleOrder(key)"></pasta-item>
    

    构建工具


    React和Vue都有自己的构建工具,你可以使用它快速搭建开发环境。React可以使用Create React App (CRA),而Vue对应的则是vue-cli。两个工具都能让你得到一个根据最佳实践设置的项目模板。

    由于CRA有很多选项,使用起来会稍微麻烦一点。这个工具会逼迫你使用WebpackBabel。而vue-cli则有模板列表可选,能按需创造不同模板,使用起来更灵活一点。

    事实上说,两个工具都非常好用,都能为你建立一个好环境。而且如果可以不配置Webpack的话,我和Jeff认为这是天大的好事。

    Chrome 开发工具


    React和Vue都有很好的Chrome扩展工具去帮助你找出bug。它们会检查你的应用,让你看到Vue或者React中的变化。你也可以看到应用中的状态,并实时看到更新。

    React的开发工具:
    https://cdn.deliciousbrains.com/content/uploads/2017/06/15151112/react-devtools.mp4

    Vue的开发工具:
    https://cdn.deliciousbrains.com/content/uploads/2017/06/15151111/vue-devtools.mp4

    主要区别


    Vue与React最后一个相似但略有不同之处是它们配套框架的处理方法。相同之处在于,两个框架都专注于UI层,其他的功能如路由、状态管理等都交由同伴框架进行处理。

    而不同之处是在于它们如何关联它们各自的配套框架。Vue的核心团队维护着vue-routervuex,它们都是作为官方推荐的存在。而React的react-routerreact-redux则是由社区成员维护,它们都不是官方维护的。

    模板 vs JSX


    React与Vue最大的不同是模板的编写。Vue鼓励你去写近似常规HTML的模板。写起来很接近标准HTML元素,只是多了一些属性。
    代码:
    <ul>
       <template v-for="item in items">
           <li>{{ item.msg }}</li>
           <li class="divider"></li>
       </template>
    </ul>
    
    这些属性也可以被使用在单文件组件中,尽管它需要在在构建时将组件转换为合法的JavaScript和HTML。
    代码:
    <ul>
      <pasta-item v-for="(item, key) in samplePasta" :item="item" :key="key" @order="handleOrder(key)"></pasta-item>
    </ul>
    
    Vue鼓励你去使用HTML模板去进行渲染,使用相似于Angular风格的方法去输出动态的内容。因此,通过把原有的模板整合成新的Vue模板,Vue很容易提供旧的应用的升级。这也让新来者很容易适应它的语法。

    React推荐你所有的模板通用JavaScript的语法扩展——JSX书写,不过这对于传统的前端开发人员需要相应的学习。同样的代码,用JSX书写的例子如下:
    代码:
    <ul className="pasta-list">
       {
           Object.keys(this.state.pastadishes).map(key =>
               <PastaItem index={key} key={key} details={this.state.pastadishes[key]} addToOrder={this.addToOrder} orders={this.state.orders[key]} />
           )
       }
    </ul>
    
    React/JSX乍看之下,觉得非常啰嗦,但使用JavaScript而不是模板来开发,赋予了开发者许多编程能力。

    状态管理 vs 对象属性


    如果你对React熟悉,你就会知道应用中的状态是(React)关键的概念。也有一些配套框架被设计为管理一个大的state对象,如Redux。此外,state对象在React应用中是不可变的,意味着它不能被直接改变,在React中你需要使用setState()方法去更新状态。
    代码:
     addToOrder(key) {
           //Make a copy of this.state
           const orders = { ...this.state.orders };
    
           //update or add
           orders[ key ] = orders[ key ] + 1 || 1;
           this.setState( { orders } );
     }
    
    在Vue中,state对象并不是必须的,数据由data属性在Vue对象中进行管理。
    代码:
    export default {
      name: 'app',
      data() {
       return {
         samplePasta: samplePasta,
         orders: {}
       }
      },
    ...
      methods: {
       handleOrder: function (key) {
    
         if (!this.orders.hasOwnProperty(key)) {
           this.$set(this.orders, key, { count: 0 });
         }
    
         this.orders[key].count += 1;
       }
      }
    }
    
    而在Vue中,则不需要使用如setState()之类的方法去改变它的状态,在Vue对象中,data参数就是应用中数据的保存者。

    不过恶心的是React出了一个霸王条款:Facebook拒修改React开源许可

    Angularjs


    Vue 的一些语法和 AngularJS 的很相似 (例如 v-if vs ng-if)。因为 AngularJS 是 Vue 早期开发的灵感来源。然而,AngularJS 中存在的许多问题,在 Vue 中已经得到解决。

    Angular


    1,MVVM(Model)(View)(View-model)
    2,模块化(Module)控制器(Contoller)依赖注入:
    3,双向数据绑定:界面的操作能实时反映到数据,数据的变更能实时展现到界面。
    4,指令(ng-click ng-model ng-href ng-src ng-if...)
    5,服务Service($compile $filter $interval $timeout $http...)
    其中双向数据绑定的实现使用了$scope变量的脏值检测,使用$scope.$watch(视图到模型),$scope.$apply(模型到视图)检测,内部调用的都是digest,当然也可以直接调用$scope.$digest进行脏检查。值得注意的是当数据变化十分频繁时,脏检测对浏览器性能的消耗将会很大,官方注明的最大检测脏值为2000个数据。

    Vue


    vue.js官网:是一套构建用户界面的 渐进式框架。与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计。Vue 的核心库只关注视图层,并且非常容易学习,非常容易与其它库或已有项目整合。另一方面,Vue 完全有能力驱动采用单文件组件和 Vue 生态系统支持的库开发的复杂单页应用。

    Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    (1)模块化,目前最热的方式是在项目中直接使用ES6的模块化,结合Webpack进行项目打包
    (2)组件化,创造单个component后缀为.vue的文件,包含template(html代码),script(es6代码),style(css样式)
    (3)路由,
    vue非常小巧,压缩后min源码为72.9kb,gzip压缩后只有25.11kb,想比Angular为144kb,可以自驾搭配使用需要的库插件,类似路由插件(Vue-router),Ajax插件(vue-resource)等

    下面从几个方面来比较一下Vue.js和Angular.js的区别

    TypeScript


    Angular 事实上必须用 TypeScript 来开发,因为它的文档和学习资源几乎全部是面向 TS 的。TS 有很多显而易见的好处 —— 静态类型检查在大规模的应用中非常有用,同时对于 Java 和 C# 背景的开发者也是非常提升开发效率的。
    然而,并不是所有人都想用 TS —— 在中小型规模的项目中,引入 TS 可能并不会带来太多明显的优势。在这些情况下,用 Vue 会是更好的选择,因为在不用 TS 的情况下使用 Angular 会很有挑战性。
    最后,虽然 Vue 和 TS 的整合可能不如 Angular 那么深入,我们也提供了官方的 类型声明 和 组件装饰器,并且知道有大量用户在生产环境中使用 Vue + TS 的组合。我们也和微软的 TS / VSCode 团队进行着积极的合作,目标是为 Vue + TS 用户提供更好的类型检查和 IDE 开发体验。

    大小和性能


    在性能方面,这两个框架都非常的快,我们也没有足够的实际应用数据来下一个结论。如果你一定想看些数据的话,你可以参考这个第三方跑分。单就这个跑分来看,Vue 似乎比 Angular 要更快一些。
    在大小方面,最近的 Angular 版本中在使用了 AOT 和 tree-shaking 技术后使得最终的代码体积减小了许多。但即使如此,一个包含了 Vuex + Vue Router 的 Vue 项目 (30kb gzipped) 相比使用了这些优化的 angular-cli 生成的默认项目尺寸 (~130kb) 还是要小的多。
    灵活性

    Vue 相比于 Angular 更加灵活,Vue 官方提供了构建工具来协助你构建项目,但它并不限制你去如何组织你的应用代码。有人可能喜欢有严格的代码组织规范,但也有开发者喜欢更灵活自由的方式。
    学习曲线

    要学习 Vue,你只需要有良好的 HTML 和 JavaScript 基础。有了这些基本的技能,你就可以非常快速地通过阅读 指南 投入开发。
    Angular 的学习曲线是非常陡峭的 —— 作为一个框架,它的 API 面积比起 Vue 要大得多,你也因此需要理解更多的概念才能开始有效率地工作。当然,Angular 本身的复杂度是因为它的设计目标就是只针对大型的复杂应用;但不可否认的是,这也使得它对于经验不甚丰富的开发者相当的不友好。

    不过就算有这么多好处,但是相比Angular2,Vue还是有很多的不足:

    1. Angular2原生Form支持: Angular2原生的Form模块功能相当强大。除了双向绑定之类的基本功能,还能通过programatic API 控制dom元素的表单行为。也有成型API提供自定义validator。这一点Vue只有v-model和第三方库。对于后台之类的重表单应用,还是Ng2有优势。
    2. 依赖注入无论你喜不喜欢DI,这就是Angular2的强大功能之一。有DI可以在不改变代码结构的情况下完成功能替换。(如,在desktop和mobile有不同功能,可以通过注入不同service实现,而共用相同的template和directive)。Vue则需要程序员自己规划代码组织,用来支持共享组件。DI也可以用于类似module local state的功能。比如,一个视频播放控件有几个子组件完成,子组件需要分享一个状态。这一点Angular2有原生的service injection pattern。而Vue则没有官方推荐。
    3. 对标准向后兼容Angular2在一些细节上对标准有更好的支持。比如 list differ 算法中 Angular2 可以支持实现了Symbol.iterator的对象,而Vue只能支持Array。对Observable和Promise,Angular2在应用的各个地方,甚至模板级别都有支持(async pipe)。而Vue需要vue-rx等第三方库支持。Angular2的组件有shadow dom的实现可以选择,而Vue目前还没有。
    4. 测试Angular2一开始就设计好了如何对组件进行测试,而Vue组件虽然也很好写测试,但是没有官方推荐的唯一标准(当然,对视图是否需要测试还有待探讨)。除此以外,Angular2还有一些小功能比如检验模板的类型安全(即,模板里能在编译器保证没有引用model未定义的变量),不过AoT本身似乎还没有稳定,所以不能算优势。对TS的支持也是Angular好,当然前提是你喜欢TS。

    Ember


    Ember 是一个全能框架。它提供了大量的约定,一旦你熟悉了它们,开发会变得很高效。不过,这也意味着学习曲线较高,而且并不灵活。这意味着在框架和库 (加上一系列松散耦合的工具) 之间做权衡选择。后者会更自由,但是也要求你做更多架构上的决定。
    也就是说,我们最好比较的是 Vue 内核和 Ember 的模板与数据模型层:

    • Vue 在普通 JavaScript 对象上建立响应,提供自动化的计算属性。在 Ember 中需要将所有东西放在 Ember 对象内,并且手工为计算属性声明依赖。
    • Vue 的模板语法可以用全功能的 JavaScript 表达式,而 Handlebars 的语法和帮助函数相比来说非常受限。
    • 在性能上,Vue 比 Ember 好很多,即使是 Ember 2.x 的最新 Glimmer 引擎。Vue 能够自动批量更新,而Ember 在关键性能场景时需要手动管理。

    Knockout


    Knockout 是 MVVM 领域内的先驱,并且追踪依赖。它的响应系统和 Vue 也很相似。它在浏览器支持以及其他方面的表现也是让人印象深刻的。它最低能支持到 IE6,而 Vue 最低只能支持到 IE9。
    随着时间的推移,Knockout 的发展已有所放缓,并且略显有点老旧了。比如,它的组件系统缺少完备的生命周期事件方法,尽管这些在现在是非常常见的。以及相比于 Vue 调用子组件的接口它的方法显得有点笨重。
    如果你有兴趣研究,你还会发现二者在接口设计的理念上是不同的。这可以通过各自创建的 simple Todo List 体现出来。或许有点主观,但是很多人认为 Vue 的 API 接口更简单结构更优雅。

    Polymer


    Polymer 是另一个由谷歌赞助的项目,事实上也是 Vue 的一个灵感来源。Vue 的组件可以粗略的类比于 Polymer 的自定义元素,并且两者具有相似的开发风格。最大的不同之处在于,Polymer 是基于最新版的 Web Components 标准之上,并且需要重量级的 polyfills 来帮助工作 (性能下降),浏览器本身并不支持这些功能。相比而言,Vue 在支持到 IE9 的情况下并不需要依赖 polyfills 来工作。
    在 Polymer 1.0 版本中,为了弥补性能,团队非常有限的使用数据绑定系统。例如,在 Polymer 中唯一支持的表达式只有布尔值否定和单一的方法调用,它的 computed 方法的实现也并不是很灵活。
    Polymer 自定义的元素是用 HTML 文件来创建的,这会限制使用 JavaScript/CSS (和被现代浏览器普遍支持的语言特性)。相比之下,Vue 的单文件组件允许你非常容易的使用 ES2015 和你想用的 CSS 预编译处理器。
    在部署生产环境时,Polymer 建议使用 HTML Imports 加载所有资源。而这要求服务器和客户端都支持 Http 2.0 协议,并且浏览器实现了此标准。这是否可行就取决于你的目标用户和部署环境了。如果状况不佳,你必须用 Vulcanizer 工具来打包 Polymer 元素。而在这方面,Vue 可以结合异步组件的特性和 Webpack 的代码分割特性来实现懒加载 (lazy-loaded)。这同时确保了对旧浏览器的兼容且又能更快加载。
    而 Vue 和 Web Component 标准进行深层次的整合也是完全可行的,比如使用 Custom Elements、Shadow DOM 的样式封装。然而在我们做出严肃的实现承诺之前,我们目前仍在等待相关标准成熟,进而再广泛应用于主流的浏览器中。

    Riot


    Riot 2.0 提供了一个类似于基于组件的开发模型 (在 Riot 中称之为 Tag),它提供了小巧精美的 API。Riot 和 Vue 在设计理念上可能有许多相似处。尽管相比 Riot ,Vue 要显得重一点,Vue 还是有很多显著优势的:

    • 过渡效果系统。Riot 现在还没有提供。
    • 功能更加强大的路由机制,Riot 的路由功能的 API 是极少的。
    • 更好的性能。Riot 使用了 遍历 DOM 树 而不是虚拟 DOM,但实际上用的还是脏检查机制,因此和 AngularJS患有相同的性能问题。
    • 更多成熟工具的支持。Vue 提供官方支持 webpack 和 Browserify,而 Riot 是依靠社区来建立集成系统。

    原始来源

    作者:: code-xzh, 阿里云云栖社区

留言

要发表留言,请注册并成为会员!