Vue3.0新特性

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

描述

Vue2Vue3在一些比较重要的方面的详细对比。

生命周期的变化

  • Vue2 -> Vue3
  • beforeCreate -> setup
  • created -> setup
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • activated -> onActivated
  • deactivated -> onDeactivated
  • errorCaptured -> onErrorCaptured
  • renderTracked -> onRenderTracked
  • renderTriggered -> onRenderTriggered

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

import { onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
onActivated,
onDeactivated,
onErrorCaptured,
onRenderTracked,
onRenderTriggered
} from "vue"; export default {
setup() {
onBeforeMount(() => {
// ...
})
onMounted(() => {
// ...
})
onBeforeUpdate(() => {
// ...
})
onUpdated(() => {
// ...
})
onBeforeUnmount(() => {
// ...
})
onUnmounted(() => {
// ...
})
onActivated(() => {
// ...
})
onDeactivated(() => {
// ...
})
onErrorCaptured(() => {
// ...
})
onRenderTracked(() => {
// ...
})
onRenderTriggered(() => {
// ...
})
}
}

使用proxy代替defineProperty

Vue2是通过数据劫持的方式来实现响应式的,其中最核心的方法便是通过Object.defineProperty()来实现对属性的劫持,该方法允许精确地添加或修改对象的属性,对数据添加属性描述符中的gettersetter存取描述符实现劫持。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 DOMVirtual DOM是一棵以JavaScript对象作为基础的树,每一个节点称为VNode,用对象属性来描述节点,实际上它是一层对真实DOM的抽象,最终可以通过渲染操作使这棵树映射到真实环境上,简单来说Virtual DOM就是一个Js对象,用以描述整个文档。

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

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

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

TypeScript的支持

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

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

打包体积变化

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

Vue3中,通过将大多数全局API和内部帮助程序移动到JavaScriptmodule.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组件的生命周期。

示例

Vue3的组件简单示例,可查看在线示例https://codesandbox.io/s/c1437?file=/src/App.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>

每日一题

https://github.com/WindrunnerMax/EveryDay

参考

https://zhuanlan.zhihu.com/p/92143274
https://www.jianshu.com/p/9d3ddaec9134
https://zhuanlan.zhihu.com/p/257044300
https://juejin.cn/post/6867123074148335624
https://juejin.cn/post/6892295955844956167
https://segmentfault.com/a/1190000024580501
https://v3.cn.vuejs.org/guide/migration/introduction.html

Vue3.0新特性的更多相关文章

  1. vue3.0新特性以及进阶路线

    Vue3.0新特性/改动 新手学习路线  ===> 起步 1. 扎实的 JavaScript / HTML / CSS 基本功.这是前置条件. 2. 通读官方教程 (guide) 的基础篇.不要 ...

  2. 浅谈Tuple之C#4.0新特性那些事儿你还记得多少?

    来源:微信公众号CodeL 今天给大家分享的内容基于前几天收到的一条留言信息,留言内容是这样的: 看了这位网友的留言相信有不少刚接触开发的童鞋们也会有同样的困惑,除了用新建类作为桥梁之外还有什么好的办 ...

  3. Java基础和JDK5.0新特性

    Java基础 JDK5.0新特性 PS: JDK:Java Development KitsJRE: Java Runtime EvironmentJRE = JVM + ClassLibary JV ...

  4. Visual Studio 2015速递(1)——C#6.0新特性怎么用

    系列文章 Visual Studio 2015速递(1)——C#6.0新特性怎么用 Visual Studio 2015速递(2)——提升效率和质量(VS2015核心竞争力) Visual Studi ...

  5. atitit.Servlet2.5 Servlet 3.0 新特性 jsp2.0 jsp2.1 jsp2.2新特性

    atitit.Servlet2.5 Servlet 3.0 新特性 jsp2.0 jsp2.1 jsp2.2新特性   1.1. Servlet和JSP规范版本对应关系:1 1.2. Servlet2 ...

  6. 背水一战 Windows 10 (1) - C# 6.0 新特性

    [源码下载] 背水一战 Windows 10 (1) - C# 6.0 新特性 作者:webabcd 介绍背水一战 Windows 10 之 C# 6.0 新特性 介绍 C# 6.0 的新特性 示例1 ...

  7. C# 7.0 新特性2: 本地方法

    本文参考Roslyn项目中的Issue:#259. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: 模式匹配 ...

  8. C# 7.0 新特性1: 基于Tuple的“多”返回值方法

    本文基于Roslyn项目中的Issue:#347 展开讨论. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: ...

  9. C# 7.0 新特性3: 模式匹配

    本文参考Roslyn项目Issue:#206,及Docs:#patterns. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# ...

随机推荐

  1. 【Nginx】配置nginx图片服务器

    想通过nginx来访问服务器上的图片 可以搭建一个nginx图片服务器. 做法如下: 先安装nginx,这里直接用yum来进行安装的 安装方法如下: https://blog.csdn.net/iml ...

  2. bootstrap弹出层嵌套弹出层后文本框不能获得焦点输入

    如图上 我从页面打开一个bootstrap弹出层 然后又在 bootstrap弹出层的基础上打开一个layui的弹出层  打开后发现文本域获取不到焦点不能输入内容 而该弹出层显示的层级体现出来了 按钮 ...

  3. java 日期与时间操作

    我们先来了解一下基本的概念 日期 2020-11-21 2020-11-22 时间 15:36:43 2020-11-21 15:36:43 时区 北京时间 2020-11-21 15:36:43 东 ...

  4. linux opt, usr文件夹说明

    linux下各文件夹介绍: https://www.pathname.com/fhs/pub/fhs-2.3.html /usr:系统级的目录,可以理解为C:/Windows/,/usr/lib理解为 ...

  5. inode占满导致No space left on device inode快速解决方法

    暂未发现其他比我这个更快的方法. 因为其他方法会展示那个非常卡的目录,导致效率极低.而我这个方法不会去展示那个目录. 查找占用的目录 find / -type d -size +1M -maxdept ...

  6. js 前端词典对象的属性和值读取

    通常服务端返回比较奇葩的数据对象,不知道该怎么将这个对象转换为可用实体,想了很久,突发奇想想到了这么个方法. 需求是这样:企业有多个产品,产品有分为很几个种类.服务端有获取产品的接口,和单独获取产品种 ...

  7. 如何配置 Slf4j

    一,前言 日常开发中经常需要在控制台输出一些信息,如果这些东西不加管理,那么很容易就被输出信息淹没.幸好,我们有日志相关的库来帮助我们格式化控制台的输出. 这篇文章将介绍如何配置 Slf4j 及其具体 ...

  8. 如何使用 Vuepress

    项目结构 ├─docs │ ├─.vuepress --vuepress相关文件路径 (主要配置) │ │ ├─dist --build 打包生成路径 (自定义) │ │ ├─nav --导航条配置 ...

  9. (Oracle)数据库用户的密码过期时间如何修改为永不过期

    Oracle的密码过期规则是用Profile来管理的,系统默认只有一个Profile(DEFAULT),该profile的密码过期规则为180天.那么如何修改Oracle数据库用户的密码过期时间为永不 ...

  10. http的响应码及含义

    1xx(临时响应) 100: 请求者应当继续提出请求. 101(切换协议) 请求者已要求服务器切换协议,服务器已确认并准备进行切换. 2xx(成功) 200:正确的请求返回正确的结果 201:表示资源 ...