1、源码升级
重写虚拟dom
优化diff
优化Tree-Shaking
优化响应式的原理
2、性能优化
打包大小减少41%
初次渲染快55%, 更新渲染快133%
内存减少54%
3、typescript
4、新特性和改变
创建项目的写法不同
vue3:vue create vue3-pro
vue2: vue init webpack vue2-pro
项目结构不同
createApp
vue3需要用createApp方法创建应用实例,参数接收一个根组件
vue2根实例是由 new Vue() 创建的,而组件实例是由 Vue.component() 创建的。
//vue2
import Vue from 'vue'
new Vue({
router,
components: { App },
template: '<App/>'
})
//vue3
import { createApp } from "vue";
const app = createApp(App);
全局方法声明不同
//vue2
Vue.prototype.$debounce = debounce;
//vue3
app.config.globalProperties.$debounce = debounce;
选项式api和组合式api
vue2只可以使用选项式api
vue3两者都可以用,最好用组合式api
生命周期不同
vue2生命周期
创建前:beforeCreate() 只有一些实例本身的事件和生命周期函数
创建后:Created() 是最早使用data和methods中数据的钩子函数
挂载前:beforeMount() 指令已经解析完毕,内存中已经生成dom树
挂载后:Mounted() dom渲染完毕页面和内存的数据已经同步
更新前:beforeUptate() 当data的数据发生改变会执行这个钩子,内存中的数据是新的,页面是旧的
更新后:Updated() 内存和页面都是新的
销毁前:beforeDestroy() 即将销毁data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作
销毁后:Destroyed() 已经销毁完毕
vue3 生命周期
beforeCreate -> setup() 开始创建组件之前,创建的是data和method
created -> setup()
beforeMount -> onBeforeMount 组件挂载到节点上之前执行的函数。
mounted -> onMounted 组件挂载完成后执行的函数
beforeUpdate -> onBeforeUpdate 组件更新之前执行的函数。
updated -> onUpdated 组件更新完成之后执行的函数。
beforeDestroy -> onBeforeUnmount 组件挂载到节点上之前执行的函数。
destroyed -> onUnmounted 组件卸载之前执行的函数。
响应式变量声明方式
- reactive
- 语句:reactive(参数)
- 参数:只能为对象
- 返回响应式对象,不管层级多深,都能响应
- 使用:获取数据值的时候直接获取,不需要加.value
- 特点:解构、扩展运算符会失去响应式
- ref
- 语句:ref(参数)
- 参数:为任意类型,从vue3.2之后,更推荐使用ref (ref底层性能做了提升 => 260%)
- 不管层级多深,都能响应
- 使用:获取数据值的时候需要加.value
- 特点:解构、扩展运算符会失去响应式
- toRef
- 语句:toRef(arg1, arg2)
- 参数:arg1 - reactive响应式对象,arg2 - 该响应对象中的某个属性。
- 返回一个ref数据,可以针对reactive创建的响应式对象中的某个属性创建一个ref,且两个之间保持引用关系
- 使用:获取数据值的时候需要加.value。
- toRef后的ref数据如果是复杂类型数据时,不是原始数据的拷贝,而是引用,改变结果数据的值也会同时改变原始数据。
- 使用场景:使用父组件传递的props数据时,要引用props的某个属性且要保持响应式连接时就很有用。
- toRefs
- 语句:toRefs(arg1)
- 参数:只接受一个参数,为reactive响应式对象
- toRef是将reactive中的某个属性转为ref,toRefs是一次性将reactive中的所有属性都转为ref
- toRefs返回的响应式对象可以进行解构、扩展运算符等操作,而不会失去响应式。
- 使用:获取数据值的时候需要加.value
- 特点:toRefs后的ref数据如果是复杂类型数据时,不是原始数据的拷贝,而是引用,改变结果数据的值也会同时改变原始数据
多事件处理
<button @click="one($event), two($event)">Submit</button>
移出sync ,v-model
绑定多个v-model
自定义属性和方法
异步组件
// vue2.x
new Vue({
components: {
'my-component': () => import('./async-com.vue'),
},
})
// vue3.x
import { createApp, defineAsyncComponent } from 'vue'
createApp({
components: {
AsyncComponent: defineAsyncComponent(() => import('./async-com.vue')),
},
})
去掉filters,直接用methods
Fragment
解决一个根元素限制
Suspense
包裹异步组件,在组件加载完毕之前显示loading
// 异步组件 child.vue
<template>
<div class="child">
<h3>我是Child组件</h3>
{{ sum }}
</div>
</template>
<script setup>
import { ref, resolveComponent } from "vue";
let sum = ref(0);
await new Promise((resolve) => {
setTimeout(() => {
resolve({ sum });
}, 3000);
});
</script>
//使用异步组件
<template>
<Suspense>
<template #default>
<child/>
</template>
<template #fallback>
<h3>加载中.....</h3>
</template>
</Suspense>
</template>
<script setup lang="ts">
import { ref, defineAsyncComponent } from "vue";
let child= defineAsyncComponent(() => import("../components/child.vue"));
</script>
Teleport
Teleport可以突破父组件的限制,让节点渲染到父组件之外的dom中,类似于react的Portals。
这种处理模式使“弹出式窗口”和“显示在页面顶部的组件”更加容易实现。通过使用 Teleport,你可以确保没有任何父级组件 CSS 规则会影响你要显示的组件,并且可以避免用 z-index 进行的黑客攻击。