vue3
抛弃了Flow
类型注释,使用TypeScript
重写了代码,增加了Composition API
基于函数的API
,解决了Vue2
中Options API
不好拆分和重用的的问题.Vue3
中使用Proxy
重写了响应式原理,并且对编译器做了优化,重写了虚拟DOM
,从而让渲染和update
的性能都有了大幅度的提升.Vue3
中移除了一些不常用的API
,如filter
.对Tree-shaking
的支持更好,过滤掉未使用的模块使打包的体积更小.
官方文档
创建项目
- 通过CDN
<script src="https://unpkg.com/vue@next"></script>
通过
Vue-cli脚手架
创建项目注:需要将@vue/cli更新至4.5.0及以上 npm update -g @vue/cli
vue create <project-name>
选择 vue3 的模板进行创建`1
2
3
4
5/*
1. vue create <project-name> 选择vue3的模板进行创建
2. cd <project-name>
3. npm run serve
*/通过
vite脚手架
创建项目注:Vite需要Node.js版本>=12.0.0
npm init vite-app <project-name> 或 yarn create vite-app <project-name>
1
2
3
4
5
6/*
1. npm init vite-app <project-name> 或 yarn create vite-app <project-name>
2. cd helloVite
3. npm install
4. npm run dev
*/
全局API-createApp
1 | // 入口文件 main.js |
Vue3 主要更新
Performance
重写了虚拟 DOM 的实现(跳过静态节点,只处理动态节点),update 性能提供,SSR 速度提高Tree shaking
全局和内部 API 已经被重构为支持 tree-shake,可以将无用模块过滤,仅打包需要和用到的部分Fragment
(空文档标签)不再限于模板中的单个根节点,Vue3 的 template 支持多个根标签,Vue2 只能由一个根标签TypeScript
更好的 TypeScript 支持Custom Renderer API
自定义渲染器 将某些部分以 canvas 画布形式展示出来而不是 Dom 方式Composition API
组合式 API组合式API,替换原有的Options API,将逻辑相关的代码组织在一起,提高可读性和可维护性,更好的重用逻辑代码(避免mixins混入时命名冲突的问题),但是依然可以使用Options API
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// Options API
export default {
data () {
return {}
},
methods: {},
cooputed () {},
watch: {},
filters: {}
}
// Composition API 所有操作聚合在 setUp 中
export default {
name: "AsyncTest",
async setup() {
let { id, name } = {id: 1, name: 'tew'};
return {
id,
name,
};
},
};Proxy
数据劫持,Vue3 中的响应式原理是基于 ES6 的 Proxy 实现的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32/*
Vue2是基于0bject.defineProperty实现数据劫持的(get/set)
+ 需要给对象中的每一个属性分别遍历做劫持「对于后期新增的属性是没有做劫持的,vue2中可以基于$set实现新增属性的劫持」
+ 对于数组中的每一项没有做劫持「vue2中重写了数组7个方法,后期通过这7个方法修改数组中的某一项,才会让视图重新渲染」
+ 默认劫持是"浅”的,vue2自动基于递归的方式实现了深度劫持
+ ES5的API,兼容IE9及以上
Vue3中的响应式数据,是基于ES6中的Proxy实现的
+ ES6的API,不兼容IE
+ Proxy除了提供get/set监听之外,还提供了其他大量的监听函数
+ Proxy无需自己依次遍历对象的每个属性,只需要代理整个对象,则所有属性都被劫持,新增属性也会被劫持
+ Proxy直接对数组每一项做代理操作数组的某一项都会触发试图更新,无需重写数组的方法
+ Proxy默认也是只对对象的第一层做代理,也需要递归遍历实现深层次代理
*/
// proxy 基本使用
// const data = {
// name: 'zhangsan',
// age: 20,
// }
const data = ['a', 'b', 'c']
const proxyData = new Proxy(data, {
get(target, key) {
return Reflect.get(target, key)
},
set(target, key, val) {
// 重复的数据,不处理
if (val === target[key]) return true
Reflect.set(target, key, val)
},
deleteProperty(target, key) {
Reflect.deleteProperty(target, key)
}
})Teleport
传送门1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28// index.html
<body>
<div id="#app"></div>
<div id="#other"></div>
</body>
// demo.vue
/*
Teleport 把当前组件的部分内容抽离出来放到页面中 非#app的容器中 基于to指定放在那个容器下
*/
<template>
<h2>Hello Vue3!</h2>
<Teleport to="#other">
<span>hello world!</span>
</Teleport>
</template>
// 渲染结果
/*
<body>
<div id="app" data-v-app="">
<h2>Hello Vue3!</h2>
<!--teleport start-->
<!--teleport end-->
</div>
<div id="other">
<span>hello world!</span>
</div>
</body>
*/Suspense
可在嵌套层级中等待嵌套的异步依赖项1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52<!-- AsyncTest.vue -->
<template>
获取的用户信息是<br />
用户编号: {{ id }}<br />
用户姓名: {{ name }}<br />
</template>
<script>
const query = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ id: 1, name: "tew" });
}, 2000);
});
};
export default {
name: "AsyncTest",
async setup() {
let { id, name } = await query();
return {
id,
name,
};
},
};
</script>
<!-- App.vue -->
<!--
<template>
<h2>Hello Vue3!</h2>
<AsyncTest /> 直接使用异步组件无法使用 需要使用 Suspense
</template>
-->
<template>
<h2>Hello Vue3!</h2>
<Suspense>
<!-- 异步组件加载成功之后显示的内容 -->
<template #default>
<AsyncTest />
</template>
<!-- 异步组件加载成功之前显示的内容 -->
<template #fallback>loading... </template>
</Suspense>
</template>
<script>
import AsyncTest from "./AsyncTest.vue";
export default {
name: "App",
components: {
AsyncTest,
},
};
</script>