Vue3的优点
diff算法的提升
vue2中的虚拟DOM是全量的对比,也就是不管是写死的还是动态节点都会一层层比较,浪费时间在静态节点上。
vue3新增静态标记(patchflag ),与之前虚拟节点对比,只对比带有patch flag 的节点,可通过flag信息得知当前节点要对比的具体内容。
例如: 当代码中包含数据时,会标记为动态。
静态提升
vue2不管是否参与更新,都会重新创建再渲染。
vue3对于不参与更新的元素,会做静态提升,只被创建一次,在渲染时直接复用即可。
Composition Api
vue2的组件内部都是options api风格,也就是在data, methods, mounted等来组织代码,这样会让逻辑很分散,每次变动需要反复查找位置。
vue3中使用setup,逻辑都放到里边。
更先进的组件
vue2不允许template下写两个组件,vue3允许,将为我们创建一个虚拟的Fragment节点。
自定义渲染api
const { createApp } from 'vue'
import App from "./src/App"
createApp(App).mount(('#app')
事件侦听器缓存
ssr渲染
更好的ts支持
按需编译,体积比vue2更小
响应式原理不同
vue2实现双向数据绑定原理,是通过ES5的Object.defineProperty,根据具体的key去读取和修改。其中的setter方法来实现数据劫持,getter实现数据修改。但是必须要先知道拦截和修改的key,所以vue2对于新增的属性无能为力,比如无法监听属性的新增和删除,数组索引和长度的变更,解决方法使用Vue.set(object, properName,value)等嵌套对象添加响应式。
function observe(obj, callback) {
let newObj = {};
Object.keys(obj).forEach((key) => {
Object.defineProperty(newObj, key, {
enumerable: true,
configurable: true,
get() {
return obj[key];
},
set(val) {
obj[key] = val;
callback(key, val);
}
})
})
return newObj;
}
let obj = observe({ name: 'alan', age: '1888' }, (key, value) => { console.log(`打印${value}`) });
在vue3中使用es5中得更快的proxy,替代了Object.defineProperty。proxy可以理解为在对象外加了一层拦截,任何人要访问该对象,都要通过这层拦截。且proxy直接对对象拦截而非属性,并返回一个对象,具有更好的响应式支持。
function obseve2(obj, callback) {
return new Proxy(obj, {
set(target, key, value) {
target[key] = value;
callback(key, value);
},
get(taget, key) {
return taget[key];
}
}
)
}
let obj2 = obseve2({ x: 1, y: 2 }, (key, value) => { console.log('坐标系') })
生命周期变化
初始化加载顺序
setup
=>beforeCreate
=>created
=>onBeforeMount
=>onMounted
vue3压缩后变快,很大程度是因为这些使用都需要引入了。
vue3中的核心api都支持了tree-shaking,这些api都是通过包引入的方式而不是直接在实例化时就注入,只会对使用到的功能或特性进行打包(按需打包),这意味着更多的功能和更小的体积。
mixins更改
在vue2 使用mixins来实现相同逻辑的抽离,每个组件只需要引入mixins,就能实现复用。
export default {
data(){
return {}
},
methods:{},
computed:{},
filters:{},
created(){},
mounted(){
console.log("我是mixins");
}
}
使用方法:
引入js文件,写入mixins:[ ]
缺点:mixins的声明周期会和引入mixins的组件的生命周期整合在一起。且minxins的生命周期比组件调用快。组件的data,methods会覆盖同名data,methods。
1.变量来源不明确(隐式传入),不利于阅读,使代码变得难以维护。
2.多个mixins的生命周期会融合到一起运行,但是同名属性、同名方法无法融合,可能会导致冲突。
3.mixins和组件可能出现多对多的关系,复杂度较高(即一个组件可以引用多个mixins,一个mixins也可以被多个组件引用)。
vue3中的改进
自定义hook的作用类似vue2的mixin,封装可复用的功能函数
import { ref,computed } from "vue";
export function useCount(){
const num = ref(10);
const doubles = computed(() => num.value * 2);
return {
num,
doubles
}
}
----------------------------------------------
import {useCount} from './useCount'
//初始化
const {num,doubles}=useCount();
父子传值的变化
在vue2中使用props传值。
在vue3中依旧使用,但是传值写法有所变化。
//Vue3父组件
<page2 :name="ageRef" @clickParent="clickParent"></page2>
function clickParent() {
console.log('我想点击父组件')
}
//子组件
<template>
<div>
我是子组件page2啊:
<div @click="emitP">{{name}}</div>
</div>
</template>
<script>
import { toRefs } from 'vue'
export default{
props:{
name: String,
},
setup(props,context){
let {name}=toRefs(props);
let {slots,emit}=context;
function emitP(){
emit('clickParent');
}
return{
name,
emitP
}
}
}
</script>
context:
包含
attrs
,slots
,emit
等数据方法:
attrs
:获取组件上的属性slots
:获取 slot 插槽的节点emit
:emit 方法(子组件向父组件传递数据)setup 函数是 Vue3 中新增的一个生命周期函数,会在
beforeCreate
之前调用。因为此时组件的data
和methods
还没有初始化,因此在 setup 中是不能使用this
的。所以 Vue 为了避免我们错误的使用,它直接将 setup 函数中的this
修改成了undefined
。并且,我们只能同步使用setup函数,不能用async将其设为异步。setup 函数接收两个参数
props
和context
, 语法为:setup(props,context){}
props
props
里面包含父组件传递给子组件的所有数据。在子组件中使用props
进行接收。
props
是响应式的, 当传入新的props
时,会及时被更新。
由于是响应式的, 所以不可以使用 ES6 解构,解构会消除它的响应式。可以使用toRefsprovide,inject 父组件向子组件传递方法和数据
api均从vue中引入。
在父组件直接provide(‘别名’,变量或方法);
在子组件直接inject(‘别名’)
碎片化节点
在vue2中,template下只允许存在一个根节点,在vue3中可以有多个跟结点