Vue3.0新特性

 Vue3.0  的设计目的可以概括为体积更小、速度更快、加强  TypeScript  支持、加强  API  设计一致性、提高自身可维护性、开放更多底层功能。

描述

从  Vue2  到  Vue3  在一些比较重要的方面的详细对比。

生命周期的变化
  • Vue2   >   Vue3
  • beforeCreate   >   setup
  • created   >   setup
  • beforeMount   >   onBeforeMount
  • mounted   >   onMounted
  • beforeUpdate   >   onBeforeUpdate
  • undated   >   onUpdated
  • beforeDestroy   >   onBeforeUnmount
  • destroyed   >   onUnmounted
  • activated   >   onActivated
  • deactivated   >   onDeactivated
  • errorCaptured   >   onErrorCaptured
  • renderTracked   >   onRenderTracked
  • renderTriggered   >   onRenderTriggered

在这里主要增加了  setup  这个生命周期,而其他的生命周期都是以  API  的形式调用,实际上随着  Composition API  的引入,我们访问这些钩子函数的方式已经改变,我们所有的生命周期都应该写在  setup  中,此方法我们应该实现大多数组件代码,并处理响应式,生命周期钩子函数等。

使用proxy代替defineProperty

 Vue2  是通过数据劫持的方式来实现响应式的,其中最核心的方法便是通过   Object.defineProperty()  来实现对属性的劫持,该方法允许精确地添加或修改对象的属性,对数据添加属性描述符中的  getter  与  setter  存取描述符实现劫持。 Vue2  之所以只能兼容到  IE8  主要就是因为  defineProperty  无法兼容  IE8  ,其他浏览器也存在轻微兼容问题。

var obj = { __x: 1 };
Object.defineProperty(obj, "x", {
    set: function(x) { console.log("watch"); this.__x = x },
    get: function() { return this.__x }
});
obj.x = 11; // watch
console.log(obj.x); // 11

 Vue3  使用  Proxy  实现数据劫持, Object.defineProperty  只能监听属性,而  Proxy  能监听整个对象,通过调用  new Proxy() ,可以创建一个代理用来代替另一个对象被称为目标,这个代理对目标对象进行了虚拟,因此该代理与目标对象表面上可以被当做同一个对象来对待。代理允许拦截在目标对象上的底层操作,而这原本是  Js  引擎的内部能力,拦截行为使用了一个能够相应特定操作的函数,即通过  Proxy  去对一个对象进行代理之后,我们将得到一个和被代理对象几乎完全一样的对象,并且可以从底层实现对这个对象进行完全的监控。 Proxy  对象是  ES6  引入的新特性, Vue3  放弃使用了  Object.defineProperty ,而选择了使用更快的原生  Proxy ,即是在兼容性方面更偏向于现代浏览器。

var target = { a: 1 };
var proxy = new Proxy(target, {
    set: function(target, key, value, receiver) {
        console.log("watch")
        return Reflect.set(target, key, value, receiver)
    },
    get: function(target, key, receiver) {
        return target[key]
    }
});
proxy.a = 11 // watch
console.log(target) // { a: 11 }
diff算法的提升

 diff  算法的基础是  Virtual DOM , Virtual DOM  是一颗以  JavaScript  对象作为基础的树,每一个节点称为  VNode ,用对象属性来描述节点,实际上它是一层对真实  DOM  的抽象,最终可以通过渲染操作在这棵树映射到真实环境上,简单来说  Virtual DOM  就是一个  Js  对象,用以描述整个文档。

 Vue2  框架通过深度递归遍历新旧两个虚拟  DOM  树,并比较每个节点上的每个属性,来确定实际  DOM  的哪些部分需要更新,由于现代  JavaScript  引擎执行的高级优化,这种有点暴力的算法通常非常快速,但是  DOM  的更新仍然涉及许多不必要的  CPU  工作。

在这里引用尤大的描述,为了实现这一点,编译器和运行时需要协同工作;编译器分析模版并生成带有优化提示的代码,而运行时尽可能获取提示并采用快速路径,这里有单个主要的优化:

  • 首先,在  DOM  树级别,我们注意到,在没有动态改变节点结构的模板指令(例如  v-if  和  v-for  )的情况下,节点结构保持完全静态,如果我们将一个模版分成由这些结构指令分隔的嵌套块,则每个块中的节点结构将再次完全静态,当我们更新块中的节点时,我们不再需要递归遍历  DOM  树,该块内的动态绑定可以在一个平面数组中跟踪,这种优化通过将需要执行的树遍历量减少一个数量级来规避虚拟  DOM  的大部分开销。
  • 其次,编译器积极地检测模版中的静态节点、子树甚至数据对象,并在生成的代码中将它们提升到渲染函数之外,这样可以避免在每次渲染时重新创建这些对象,从而大大提高内存使用率并减少垃圾回收的频率。
  • 第三,在元素级别,编译器还根据需要执行的更新类型,为每个具有动态绑定的元素生成一个优化标志,例如具有动态类绑定或许多静态属性的元素将收到一个标志,提示只需要进行类检测,运行时将获取这些提示并采用专用的快速路径。
TypeScript的支持

 Vue2  中使用的都是  Js ,其本身并没有类型系统的概念,现如今  TypeScript  异常火爆,对于大规模很大的项目,没有类型声明,后期维护和代码的阅读都是头疼的事情,虽然  Vue2  实际上也是可以使用  TS  的,但是支持并不算也别完美,此外  Vue2  的源码也是使用  Facebook  的   Flow  做类型检查。

最终  Vue3  借鉴了  React Hook  实现了更自由的编程方式,提出了  Composition API ,   Composition API  不需要通过指定一长串选项来定义组件,而且允许用户像编写函数一样自由地表达、组合和重用有状态的组件逻辑,同时提供出色的  TypeScript  支持。

打包体积变化

 Vue2  官方说明运行时打包  23k ,单着只是没安装依赖的时候,随之依赖包和框架特性的增多,有时候不必要的,未使用的代码文件都被打包了进去,所以后期项目大了,打包文件会特别多还很大。

在  Vue3  中,通过将大多数全局  API  和内部帮助程序移动到  JavaScript  的  module.exports  属性上实现这一点,这允许现代模式下的  module bundler  能够静态地分析模块依赖关系,并删除与未使用的  module.exports  属性相关的代码,模版编译器还生成了对  Tree Shaking  摇树优化友好的代码,只有在模版中实际使用某个特性时,该代码才导入该特性的帮助程序,尽管增加了许多新特性,但  Vue3  被压缩后的基线大小约为  10KB ,不到  Vue2  的一半。

非兼容变更

Vue3相对于Vue2的非兼容的变更概括,详情可以查阅https://v3.cn.vuejs.org/guide/migration/introduction.html

全局API
  • 全局Vue API已更改为使用应用程序实例。
  • 全局和内部API已经被重构为可tree-shakable
模板指令
  • 组件上v-model用法已更改,替换v-bind.sync
  • <template v-for>和非v-for节点上key用法已更改。
  • 在同一元素上使用的v-ifv-for优先级已更改。
  • v-bind="object"现在排序敏感。
  • v-on:event.native修饰符已移除。
  • v-for中的ref不再注册ref数组。
组件
  • 只能使用普通函数创建功能组件。
  • functional属性在SFC单文件组件<template>functional组件选项被抛弃。
  • 异步组件现在需要defineAsyncComponent方法来创建。
  • 组件事件现在需要在emits选项中声明。
渲染函数
  • 渲染函数API改变。
  • scopedSlots property已删除,所有插槽都通过slots作为函数暴露。
  • listeners被移除或整合到attrs。
  • $attrs现在包含class and style attribute
自定义元素
  • 自定义元素白名单现在已经在编译时执行。
  • 对特殊的is prop的使用只严格限制在被保留的<component>标记中。
其他小改变
  • destroyed生命周期选项被重命名为unmounted
  • beforeDestroy生命周期选项被重命名为beforeUnmount
  • default prop工厂函数不再可以访问this上下文。
  • 自定义指令API已更改为与组件生命周期一致。
  • data选项应始终被声明为一个函数。
  • 来自mixindata选项现在为浅合并。
  • Attribute强制策略已更改。
  • 一些过渡class被重命名。
  • <TransitionGroup>不再默认渲染包裹元素。
  • 当侦听一个数组时,只有当数组被替换时,回调才会触发,如果需要在变更时触发,则需要指定deep选项。
  • 没有特殊指令的标记v-if/else-if/elsev-forv-slot<template>现在被视为普通元素,并将生成原生的<template>元素,而不是渲染其内部内容。
  • Vue2中,应用根容器的outerHTML将替换为根组件模板,如果根组件没有模板/渲染选项,则最终编译为模板,Vue3现在使用应用容器的innerHTML,这意味着容器本身不再被视为模板的一部分。
移除API
  • keyCode支持作为v-on的修饰符。
  • $on、$off和$once实例方法。 
  • 过滤器方法,建议用计算属性或方法代替过滤器。
  • 内联模板attribute
  • $children实例property
  • $destroy实例方法,用户不应再手动管理单个Vue组件的生命周期。
<template>
  <div>
    <div>{{ msg }}</div>
    <div>count: {{ count }}</div>
    <div>double-count: {{ doubleCount }}</div>
    <button @click="multCount(3)">count => count*3</button>
  </div>
</template>

<script>
import { onMounted, reactive, computed } from "vue";
export default {
  name: "App",
  components: {},
  setup: () => {
    /* 定义data */
    const data = reactive({
      msg: "Hello World",
      count: 1,
    });

    /* 处理生命周期 */
    onMounted(() => {
      console.log("Mounted");
    });

    /* 处理computed */
    const computeds = {
      doubleCount: computed(() => data.count * 2),
    };

    /* 定义methods */
    const methods = {
      multCount: function (n) {
        data.count = data.count * n;
      },
    };

    /* 返回数据 */
    return Object.assign(data, computeds, methods);
  },
};
</script>

<style>
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值