写在前面
小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
一、前言
Vue3.x从2020年9月18日发布第一个One Piece版本,到现在一直在更新优化;中文版的官方文档也已经放出;那么作为终端用户的我们来看下Vue3.x新增了哪些功能和特性。今天小编就带大家通过和Vue2.x的对比一起来学习入门。
注意: Vue3.x 是兼容 Vue2.x 版本的,也就是说我们再日常工作中 可以在 Vue3.x 中使用 Vue2.x 的相关语法 但是当你真正开始使用 Vue3 写项目时 你会发现他比 Vue2.x 方便很多
二、Vue3.x优点
- Performance:性能优化
- Tree-shaking support:支持摇树优化
- Composition API:组合API
- Fragment,Teleport,Suspense:新增的组件
- Better TypeScript support:更好的TypeScript支持
- Custom Renderer API:自定义渲染器
三、环境要求
- Node.js 版本 >= 12.0.0
四、包管理器
包管理器它可以让你使用并分享 全世界开发者的(例如 JavaScript)代码常用的有以下几种:
4.1 [npm]
4.2 yarn
- 稳定版: v1.22.4
- Node 版本支持: ^4.8.0 || ^5.7.0 || ^6.2.2 || >=8.0.0
- 安装方式:在 Windows 系统中有三种安装 Yarn 的方式
4.3 [pnpm]
4.4 [yi]
五、脚手架
脚手架作为项目工程创建的入口,可快速创建标准的Vue项目,下面从脚手架的按照方面加以说明。
5.1 Vue2.x
- 全局安装Vue2.x脚手架
yarn global add vue/cli # 或 npm install -g vue/cli
5.2 Vue3.x
- 全局安装Vue3.x脚手架
yarn global add @vue/cli # OR yarn global add @vue/cli@next # 或 npm install -g @vue/cli
- 然后在 Vue 项目中运行
vue upgrade --next
- 项目创建
vue create my-project
- 配置项选择
Vue CLI v5.0.0-beta.7 ? Please pick a preset: (Use arrow keys) > ts-admin ([Vue 2] less, babel, typescript, pwa, router, vuex, eslint, unit-jest) vue3-ts-admin ([Vue 2] typescript, pwa, router, vuex, eslint) Default ([Vue 2] babel, eslint) Default (Vue 3) ([Vue 3] babel, eslint) Manually select features
- 选择 Manually select features
Vue CLI v5.0.0-beta.7 ? Please pick a preset: Manually select features ? Check the features needed for your project: (*) Choose Vue version (*) Babel (*) TypeScript (*) Progressive Web App (PWA) Support (*) Router (*) Vuex (*) CSS Pre-processors (*) Linter / Formatter (*) Unit Testing (*) E2E Testing
- Choose Vue version
Vue CLI v5.0.0-beta.7 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Lint er, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 2.x > 3.x
- Use class-style component syntax?
Vue CLI v5.0.0-beta.7 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Lint er, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 3.x ? Use class-style component syntax? (y/N)
- babel
Vue CLI v5.0.0-beta.7 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Lint er, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 3.x ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? (Y/n)
- Use history mode for router?
Vue CLI v5.0.0-beta.7 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Lint er, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 3.x ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes ? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n)
- Pick a CSS pre-processor
Vue CLI v5.0.0-beta.7 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Lint er, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 3.x ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): (Use arrow keys) > Sass/SCSS (with dart-sass) Less Stylus
- Pick a linter / formatter config
Vue CLI v5.0.0-beta.7 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Lint er, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 3.x ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Less ? Pick a linter / formatter config: ESLint with error prevention only ESLint + Airbnb config > ESLint + Standard config ESLint + Prettier
- Pick additional lint features
Vue CLI v5.0.0-beta.7 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Lint er, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 3.x ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Less ? Pick a linter / formatter config: Standard ? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection) >(*) Lint on save ( ) Lint and fix on commit
- Pick a unit testing solution
Vue CLI v5.0.0-beta.7 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Lint er, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 3.x ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Less ? Pick a linter / formatter config: Standard ? Pick additional lint features: Lint on save, Lint and fix on commit ? Pick a unit testing solution: (Use arrow keys) > Jest Mocha + Chai
- Cypress
Vue CLI v5.0.0-beta.7 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Lint er, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 3.x ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Less ? Pick a linter / formatter config: Standard ? Pick additional lint features: Lint on save, Lint and fix on commit ? Pick a unit testing solution: Jest ? Pick an E2E testing solution: (Use arrow keys) > Cypress (Test in Chrome, Firefox, MS Edge, and Electron) Nightwatch (WebDriver-based) WebdriverIO (WebDriver/DevTools based)
- Where do you prefer placing config for Babel, ESLint, etc.?
Vue CLI v5.0.0-beta.7 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Lint er, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 3.x ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Less ? Pick a linter / formatter config: Standard ? Pick additional lint features: Lint on save, Lint and fix on commit ? Pick a unit testing solution: Jest ? Pick an E2E testing solution: Cypress ? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys) > In dedicated config files In package.json
- Save preset as
Vue CLI v5.0.0-beta.7 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Lint er, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 3.x ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Less ? Pick a linter / formatter config: Standard ? Pick additional lint features: Lint on save, Lint and fix on commit ? Pick a unit testing solution: Jest ? Pick an E2E testing solution: Cypress ? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files ? Save this as a preset for future projects? Yes ? Save preset as: my-project
说明
Vue3.x 可以创建Vue2.x项目
六、生命周期
在vue3.x中,新增了一个setup
生命周期函数,setup
执行的时机是在beforeCreate
生命函数之前执行,因此在这个函数中是不能通过this
来获取实例的;同时为了命名的统一,将beforeDestroy
改名为beforeUnmount
,destroyed
改名为unmounted
。
6.1 Vue2.x
生命周期图示
生命周期
- beforeCreate:
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeDestroy
- destroyed
- errorCaptured
6.2 Vue3.x
生命周期图示
生命周期
- setup
- onBeforeMount
- onMounted
- onBeforeUpdate
- onUpdated
- onBeforeUnmount
- onUnmounted
- onErrorCaptured
6.3 对照表
| 2.0 周期名称 | 3.0 周期名称 | 说明 | | beforeCreate | setup | 组件创建之前 | | created | setup | 组件创建完成 | | beforeMount | onBeforeMount | 组件挂载之前 | | mounted | onMounted | 组件挂载完成 | | beforeUpdate | onBeforeUpdate | 数据更新,虚拟 DOM 打补丁之前 | | updated | onUpdated | 数据更新,虚拟 DOM 渲染完成 | | beforeDestroy | onBeforeUnmount| 组件销毁之前 | | destroyed | onUnmounted | 组件销毁后 |
生命周期 | Vue2.x | Vue3.x | 说明 |
setup | N | Y | beforeCreate、created由setup()代替 |
beforeCreate | Y | setup | 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前执行,此时组件实例还未创建,通常用于插件开发中执行一些初始化任务 |
created | Y | setup | 组件实例已经创建完成,并配置了数据观测 (data observer),property 和方法的运算,watch/event 事件回调。但是还没有挂载DOM,此阶段可用于异步数据获取 |
beforeMount | Y | onBeforeMount | 在挂载开始之前被调用:相关的 render 函数首次被调用 |
mounted | Y | onMounted | 组件实例被挂载后完成,DOM已创建,此阶段可用于访问数据和DOM元素,但不会保证所有子组件都一起被挂载。如果您希望整个视图都完成渲染可以在 mounted 内部使用 vm.$nextTick |
beforeUpdate | Y | onBeforeUpdate | 数据更新前调用,可用于获取更新前的状态。可在这里 手动移除已经添加的事件监听器 |
updated | Y | onUpdated | 此函数执行的时候。DOM已经更新。updated 不会保证所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以在 updated 里使用 vm.$nextTick |
beforeDestroy | Y | onBeforeUnmount | 实例销毁之前调用。在这一步,实例仍然完全可用,此时可以取消定时器和订阅事件 |
destroyed | Y | onUnmounted | 卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载 |
errorCaptured | Y | onErrorCaptured | 错误时调用 |
注意
vue3.x
的生命周期执行发生在vue2.x
生命周期的前面setup
这个生命周期发生在beforeCreate
和created
之前- 两种形式的生命周期函数是可以共存,它们都会被执行
6.4 代码案例
<script lang="ts"> import { Options, Vue } from 'vue-class-component' import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, reactive, ref } from 'vue' import HelloWorld from '@/components/HelloWorld.vue' // @ is an alias to /src @Options({ props: { msg: String }, components: { HelloWorld } }) export default class Home extends Vue { setup ():void { console.log("类似于created") // 挂载的生命周期 onBeforeMount(() => { console.log('Vue3.0类似于beforeMount ') }) onMounted(() => { console.log('Vue3.0类似于mounted ') }) // 跟新阶段的生命周期 onBeforeUpdate(() => { console.log('Vue3.0类似于beforeUpdate ') }) onUpdated(() => { console.log('Vue3.0类似于 updated ') }) // 销毁阶段生命周期 onBeforeUnmount(() => { console.log('Vue3.0类似beforeDestory ') }) onUnmounted(() => { console.log('Vue3.0类似于destoryed') }) } beforeCreate (): void { console.log('vue2.0 beforeCreate') } created ():void { console.log('vue2.0 created') } beforeMount ():void { console.log('vue2.0 beforeMount') } mounted ():void { console.log('vue2.0 mounted') } beforeUpdate ():void { console.log('vue2.0 beforeUpdate') } updated ():void { console.log('vue2.0 updated') } beforeUnmount ():void { console.log('vue2.0 beforeDestroy') } // destroyed==> unmounted unmounted ():void { console.log('vue2.0 destroyed') } } </script>
同时,vue3新增了生命周期钩子,我们可以通过在生命周期函数前加
on
来访问组件的生命周期,我们可以使用以下生命周期钩子:
- onBeforeMount
- onMounted
- onBeforeUpdate
- onUpdated
- onBeforeUnmount
- onUnmounted
- onErrorCaptured
- onRenderTracked
- onRenderTriggered
我们在setup中挂载生命周期钩子,当执行到对应的生命周期时,就调用对应的钩子函数:
import { onBeforeMount, onMounted } from "vue"; export default { setup() { onBeforeMount(() => { // beforeMount代码执行 }); onMounted(() => { // mounted代码执行 }); }, }
七、 Vue3.x新增功能
7.1 响应式API
Vue3.x
中新增reactive
相当于Vue2.x中的Vue.observable
reactive
函数只接收object
和array
等复杂数据类型ref
创建基本数据类型,比如字符串和数值等
reactive
主要负责复杂数据结构,而ref
主要处理基本数据结构;但是ref
本身也是能处理对象和数组的:
- 使用
reactive
来为JS对象创建响应式状态
import { reactive, toRefs } from "vue"; const user = reactive({ name: 'kuaizhidao', age: 6, }); user.name = '快智岛'
- 对于一些基本数据类型,比如字符串和数值等,我们想要让它变成响应式,也可以通过
reactive
函数创建对象的方式,但是Vue3.x
提供了另一个函数ref
import { ref } from "vue"; const num = ref(0); const str = ref(""); const bool = ref(true); num.value++; console.log(num.value); str.value = "new val"; console.log(str.value); bool.value = false; console.log(male.value);
ref
返回的响应式对象是只包含一个名为value参数的RefImpl对象,在js中获取和修改都是通过它的value属性;但是在模板中被渲染时,自动展开内部的值,因此不需要在模板中追加.value
。
<template> <div> <span>{{ count }}</span> <button @click="count ++">Increment count</button> </div> </template> <script> import { ref } from 'vue' export default { setup() { const count = ref(0) return { count } } } </script>
ref
处理对象和数组
import { ref } from "vue"; // 处理对象 const obj = ref({ name: "kuaizhidao", age: 6, }); setTimeout(() => { obj.value.name = "快智岛"; }, 1000); // 处理数组 const list = ref([1, 2, 3, 4, 6]); setTimeout(() => { list.value.push(7); }, 2000);
7.2 装饰器(decorators)
Vue Class Component是一个可以让你使用Class风格语法编写Vue组件的库.
1. Class 组件
@Component
装饰器可以让你能创建一个基于Class的Vue组件:
<template> <div>{{ message }}</div> </template> <script> import Vue from 'vue' import Component from 'vue-class-component' // HelloWorld class will be a Vue component @Component export default class Kuaizhidao extends Vue {} </script>
2. Data
使用Class属性来初始化 data
<template> <div>{{ message }}</div> </template> <script> import Vue from 'vue' import Component from 'vue-class-component' @Component export default class HelloWorld extends Vue { // 定义 component 的 data message = 'Hello World!' } </script>
The above component renders 上面的组件会在
中的组件data message
中渲染Hello World!
注意如果初始化的值是
undefined
, Class属性将不是响应式的, 意思就是当其发生修改后, 将不会被侦测到:
<template> <div>{{ message }}</div> </template> <script> import Vue from 'vue' import Component from 'vue-class-component' @Component export default class HelloWorld extends Vue { // `message` 将不是响应式数据 message = undefined } <script>
为了防止这种情况, 你需要使用
null
来赋值, 或者使用data
钩子来代替:
import Vue from 'vue' import Component from 'vue-class-component' @Component export default class HelloWorld extends Vue { // `message` 将是响应式 message = null data() { return { // `name` 将是响应式的, 因为在data钩子里 name: undefined } } }
3. Methods
组件 methods
将直接定义在Class方法属性中
<template> <button v-on:click="handleOK">Click</button> </template> <script> import Vue from 'vue' import Component from 'vue-class-component' @Component export default class HelloWorld extends Vue { // 定义一个组件方法 handleOK() { console.log('Hello World!') } } </script>
4. Computed Properties
计算属性可以通过Class属性的 getter / setter
定义
<template> <input v-model="name"> </template> <script> import Vue from 'vue' import Component from 'vue-class-component' @Component export default class HelloWorld extends Vue { firstName = 'Kuai' lastName = 'zhidao' // 定义计算属性的 getter get name() { return this.firstName + ' ' + this.lastName } // 定义计算属性的 setter set name(value) { const splitted = value.split(' ') this.firstName = splitted[0] this.lastName = splitted[1] || '' } } </script>
5. Hooks
data
, render
以及所有Vue生命周期钩子可以直接在Class属性方法中直接定义, 但是你不能在实例本身上调用他们. 当定义自定义方法时, 你应该回避这些保留名
import Vue from 'vue' import Component from 'vue-class-component' @Component export default class HelloWorld extends Vue { // 定义生命周七钩子函数 mounted() { console.log('mounted') } // 定义渲染函数 render() { return <div>Hello World!</div> } }
八、Options API 和 Composition API区别
Options API
约定了我们该在哪个位置做什么事,在一定程度上也强制我们进行了代码分割。现在用 Composition API
,不再这么约定了,代码组织非常灵活,我们的控制代码写在setup
里面即可。
setup
>beforeCreate
(表示组件刚刚被创建出来,组件的data
和methods
还没有初始化好)>created
(表示组件刚刚被创建出来,并且组件的data
和methods
已经初始化好)setup
函数是Composition API
(组合API)的入口- 由于在执行
setup
函数的时候,还没有执行created
生命周期方法,所以在setup
函数中,无法使用data
和methods
的变量和方法 - 在
setup
中没有this
,由于我们不能在setup
函数中使用data
和methods
,所以Vue
为了避免我们错误的使用,直接将setup
函数中的this
修改成了undefined
- 在
setup
函数中定义的变量和方法最后都是需要return
出去的 不然无法再模板中使用 setup
函数只能是同步的不能是异步的
Options API | Composition API | 说明 |
props 里面设置接收参数 | Composition API 不再约定 |
控制代码写在 setup 里面即可 |
data 里面设置变量 | Composition API 不再约定 |
|
computed 里面设置计算属性 | Composition API 不再约定 |
|
watch 里面设置监听属性 | Composition API 不再约定 |
|
methods 里面设置事件方法 | Composition API 不再约定 |