Vue3和Vue2比较

231 阅读3分钟

vue3的template支持不用根标签包裹

减少便签层级,减少内存占用。

<template>
12
</template>
能在页面中渲染,不报错

router写法不一样

在vue3中,定义了一个vue-router然后引入的useRoute,useRouter 相当于vue2的 this.$routethis.$router, 但是其他之前vue2的操作都可以进行。

比如进行跳转不是用this.$router.push('/about'),而是useRouter().push('/about')

import {useRouter,useRoute} from "vue-router";
setup(){
  const router= useRouter()
  const route= useRoute()
  function jump(){
    router.push('/about')
  }
  onMounted(()=>{
    let path = route.path
    let query = route.query
  })
  return{
    jump
  }
}

全局API写法不一样

2.x 全局 API(Vue3.x 实例 API (app)
Vue.config.xxxxapp.config.xxxx
Vue.config.productionTip移除
Vue.componentapp.component
Vue.directiveapp.directive
Vue.mixinapp.mixin
Vue.useapp.use
Vue.prototypeapp.config.globalProperties

钩子函数写法不一样

选项式 APIHook inside setup
beforeCreateNot needed*
createdNot needed*
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
errorCapturedonErrorCaptured
renderTrackedonRenderTracked
renderTriggeredonRenderTriggered
activatedonActivated
deactivatedonDeactivated

生命周期原理不一样,借用图片:

image.png

image.png

在vue2中,我们是先new Vue(),然后执行beforeCreatecreated接着问你有没有vm.$mount(el),有,才继续执行,但是在vue3中,它是先全部准备好后然后再进行函数。

其实在vue3中生命周期没有多大的改变,只是改变了改变了销毁前,和销毁,让它更加语义化了 beforeDestroy改名为beforeUnmount,destroyed改名为unmounted

移除vue2的一些写法

  • 移除keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes

  • 移除v-on.native修饰符

  • 移除过滤器(filter

vue3新增Teleport标签

teleport 提供了一种有趣的方法,允许我们控制在 DOM 中哪个父节点下渲染了 HTML,而不必求助于全局状态或将其拆分为两个组件。

其实就是可以不考虑你写在什么位置,你可以定义teleport在任意标签里进行定位等(常见操作为模态框),除了body外,还可以写css选择器(id,class

// 在同一目标上使用多个 teleport
<teleport to="#modals">
  <div>A</div>
</teleport>
<teleport to="#modals">
  <div>B</div>
</teleport>

<!-- result-->
<div id="modals">
  <div>A</div>
  <div>B</div>
</div>

具体可参考:teleport

vue3 watch可以监听多个属性

响应式原理不一样

可参考精品文章:vue3 的响应式和以前有什么区别,Proxy 无敌?

Proxy 和 Reflect - 掘金 (juejin.cn)

Proxy 功能强大得多,因为它将所有东西转发到目标对象。

Proxy中apply的作用:

function delay(f, ms) {
  return new Proxy(f, {
    apply(target, thisArg, args) {
      setTimeout(() => target.apply(thisArg, args), ms);
    }
  });
}

function sayHi(user) {
  alert(`Hello, ${user}!`);
}

sayHi = delay(sayHi, 3000);

alert(sayHi.length); // 1 (*) proxy 转发“获取 length” 操作到目标对象

sayHi("John"); // Hello, John! (3秒后)

解释为什么要用Reflect,它的receiver参数可以读取属性所在的this指向

let user = {
  _name: "Guest",
  get name() {
    return this._name;
  }
};

let userProxy = new Proxy(user, {
  get(target, prop, receiver) {
    return target[prop]; // (*) target = user
  }
});

let admin = {
  __proto__: userProxy,
  _name: "Admin"
};

// Expected: Admin
alert(admin.name); // 输出:Guest (?!?)

为了解决这种情况,我们需要 get 钩子的第三个参数 receiver。它保证传递正确的 this 给 getter。在我们的情况下是 admin

如何为 getter 传递上下文?对于常规函数,我们可以使用 call/apply,但这是一个 getter,它不是“被调用”的,只是被访问的。

Reflect.get 可以做到的。如果我们使用它,一切都会正常运行。

这是更正后的变体:

let user = {
  _name: "Guest",
  get name() {
    return this._name;
  }
};

let userProxy = new Proxy(user, {
  get(target, prop, receiver) { // receiver = admin
    return Reflect.get(target, prop, receiver); // (*)
  }
});


let admin = {
  __proto__: userProxy,
  _name: "Admin"
};

alert(admin.name); // Admin

现在 receiver,保留了对正确 this 的引用(即admin)的引用,该引用将在 (*) 行中使用Reflect.get传递给getter。

MapSetDatePromise需要借助于Reflect完成代理

diff算法不一样

可精读我的另一篇:react+vue2+vue3 diff算法分析及比较

打包优化

vue3 中针对全局 和内部的API进行了重构,并考虑到tree-shaking的支持。因此,全局 API 现在只能作为ES模块构建的命名导出进行访问。 mp.weixin.qq.com/s/PdG6YYi4_…

静态标记

diff算法不比较静态标签

事件缓存

静态提升