首页
Javascript
Html
Css
Node.js
Electron
移动开发
小程序
工具类
服务端
浏览器相关
前端收藏
其他
关于

Vue3对比Vue2,删除了哪些东西,有哪些改进和变化?

2022年11月22日 发布 阅读(74) 作者:Jerman

一、工具上的变化

二、vue源码上的变化

  • vue3源码使用了Typescript实现,更好的支持了Typescript https://www.typescriptlang.org/
  • Proxy 替换掉 Object.defineProperty
    • Proxy代理的是整个对象,Object.defineProperty只代理某些属性
    • Proxy可以监听对象上新增的属性,Object.defineProperty不可以
    • Proxy可以监听数组的新增修改,Object.defineProperty不可以(长度的变化都不行,导致数据的一些方法不能被监听,只能用$set)
  • 响应式的改变
    通过ref实现,速度更快,由refreactive替换写在data中的数据(底层也是要转换成ref或reactive的)
  • 引入了tree-shaking,减少了打包体积
  • 编译的优化,引入了Block概念,把节点分为了静态(不需要跟踪)和动态(需要跟踪)

三、新增内置组件/属性

四、生命周期函数

参考:https://cn.vuejs.org/guide/essentials/lifecycle.html#lifecycle-diagram

vue2 option apivue3 option apivue 3 composition api
beforeCreatebeforeCreate不再需要,代码可直接置于setup中
createdcreated不再需要,代码可直接置于setup中
beforeMountbeforeMountonBeforeMount
mountedmountedonMounted
beforeUpdatebeforeUpdateonBeforeUpdate
updatedupdatedonUpdated
beforeDestroy改为—> beforeUnmountonBeforeUnmount
destroyed改为—> unmountedonUnmounted
errorCapturederrorCapturedonErrorCaptured
-新增—> renderTrackedonRenderTracked
-新增—> renderTriggeredonRenderTriggered

五、minxin

六、模板

  • vue3中模板可以有多个根节点(div),vue2只能有1个
  • vue3中v-if和v-for可以写一起,v-if的优先级更高
  • vue3去掉了.sync,直接使用v-model即可

七、API

Vue2—->Vue3的变化细节

  • 异步组件 https://cn.vuejs.org/guide/components/async.html

    1. //vue2
    2. const asyncComponent = () => import('./asyncComponent.vue')
    3. // 或者
    4. const asyncComponent = {
    5. component: () => import('./asyncComponent.vue')
    6. }
    1. //vue3 ,需要使用defineAsyncComponent 声明
    2. // ... 像使用其他一般组件一样使用 AsyncComp
    3. import { defineAsyncComponent } from 'vue'
    4. const AsyncComp = defineAsyncComponent(() => {
    5. // 必须返回一个Promise对象
    6. return new Promise((resolve, reject) => {
    7. // ...从服务器获取组件
    8. resolve(/* 获取到的组件 */)
    9. })
    10. })
    1. //vue2的component改成了loader
    2. //vue3 高级用法
    3. const AsyncComp = defineAsyncComponent({
    4. // 加载函数
    5. loader: () => import('./Foo.vue'),
    6. // 加载异步组件时使用的组件
    7. loadingComponent: LoadingComponent,
    8. // 展示加载组件前的延迟时间,默认为 200ms
    9. delay: 200,
    10. // 加载失败后展示的组件
    11. errorComponent: ErrorComponent,
    12. // 如果提供了一个 timeout 时间限制,并超时了
    13. // 也会显示这里配置的报错组件,默认值是:Infinity
    14. timeout: 3000
    15. })
  • 属性布尔值/非布尔值/枚举值变化

  • $attrs 现在包含了所有传递给组件的 attribute,包括 class 和 style
    详情参考:https://v3-migration.vuejs.org/zh/breaking-changes/attrs-includes-class-style.html

  • 移除了$listeners,合并到了$attrs https://v3-migration.vuejs.org/zh/breaking-changes/listeners-removed.html

    1. // vue2
    2. <template>
    3. <label>
    4. <input type="text" v-bind="$attrs" v-on="$listeners" />
    5. </label>
    6. </template>
    7. <script>
    8. export default {
    9. inheritAttrs: false
    10. }
    11. </script>
    1. //vue3
    2. <template>
    3. <label>
    4. <input type="text" v-bind="$attrs" />
    5. </label>
    6. </template>
    7. <script>
    8. export default {
    9. inheritAttrs: false
    10. }
    11. </script>
  • 移除了$children https://v3-migration.vuejs.org/zh/breaking-changes/children.html

  • 移除propsData

    1. // vue2
    2. const Comp = Vue.extend({
    3. props: ['username'],
    4. template: '<div>{{ username }}</div>'
    5. })
    6. new Comp({
    7. propsData: {
    8. username: 'Evan'
    9. }
    10. })
    1. // vue3必须使用createApp方法
    2. const app = createApp(
    3. {
    4. props: ['username'],
    5. template: '<div>{{ username }}</div>'
    6. },
    7. { username: 'Evan' }
    8. )
  • props 默认值函数不可访问this对象,但可以使用inject

    1. //vue3
    2. import { inject } from 'vue'
    3. export default {
    4. props: {
    5. theme: {
    6. default (props) {
    7. // `props` 是传递给组件的原始值。
    8. // 在任何类型/默认强制转换之前
    9. // 也可以使用 `inject` 来访问注入的 property
    10. // 使用inject后,实例中可直接使用this.theme调用
    11. return inject('theme', 'default-theme')
    12. }
    13. }
    14. }
    15. }
  • 自定义指令 https://v3-migration.vuejs.org/zh/breaking-changes/custom-directives.html
    created - 新增!在元素的 attribute 或事件监听器被应用之前调用。
    bind → beforeMount
    inserted → mounted
    beforeUpdate:新增!在元素本身被更新之前调用,与组件的生命周期钩子十分相似。
    update → 移除!该钩子与 updated 有太多相似之处,因此它是多余的。请改用 updated。
    componentUpdated → updated
    beforeUnmount:新增!与组件的生命周期钩子类似,它将在元素被卸载之前调用。
    unbind -> unmounted

    1. // vue3
    2. const MyDirective = {
    3. created(el, binding, vnode, prevVnode) {}, // 新增
    4. beforeMount() {},
    5. mounted() {},
    6. beforeUpdate() {}, // 新增
    7. updated() {},
    8. beforeUnmount() {}, // 新增
    9. unmounted() {}
    10. }
  • Data选项的变化
    • 不再支持直接使用Object,只接受返回objectfunction
  • emits变化
    emits可以跟props一样,可以声明组件可触发的事件(vue2不可以显性的声明)
    1. // vue3
    2. <template>
    3. <div>
    4. <p>{{ text }}</p>
    5. <button v-on:click="$emit('accepted')">OK</button>
    6. </div>
    7. </template>
    8. <script>
    9. export default {
    10. props: ['text'],
    11. emits: ['accepted']
    12. }
    13. </script>
  • 事件API

    • VUE3在实例中移除了 $on$off$once 方法,只保留了$emit
    • eventBus里可以实现$on$off$once 方法,不推荐使用(难以维护)

      1. // eventBus.js
      2. import emitter from 'tiny-emitter/instance'
      3. export default {
      4. $on: (...args) => emitter.on(...args),
      5. $once: (...args) => emitter.once(...args),
      6. $off: (...args) => emitter.off(...args),
      7. $emit: (...args) => emitter.emit(...args),
      8. }

      替代Even Bus的方案

      1. Props 和事件应该是父子组件之间沟通的首选。兄弟节点可以通过它们的父节点通信。
      2. provide / inject 允许一个组件与它的插槽内容进行通信。这对于总是一起使用的紧密耦合的组件非常有用。
      3. provide / inject 也能够用于组件之间的远距离通信。它可以帮助避免“prop 逐级透传”,即 prop 需要通过许多层级的组件传递下去,但这些组件本身可能并不需要那些 prop
      4. Prop 逐级透传也可以通过重构以使用插槽来避免。如果一个中间组件不需要某些 prop,那么表明它可能存在关注点分离的问题。在该类组件中使用 slot 可以允许父节点直接为它创建内容,因此 prop 可以被直接传递而不需要中间组件的参与。
      5. 全局状态管理,比如 Pinia
  • 删除了实例中的$filter过滤器
    https://v3-migration.vuejs.org/zh/breaking-changes/filters.html

    1. // vue3使用globalProperties 注册
    2. // main.js
    3. const app = createApp(App)
    4. app.config.globalProperties.$filters = {
    5. currencyUSD(value) {
    6. return '$' + value
    7. }
    8. }
    9. // 所有组合可使用
    10. <template>
    11. <h1>Bank Account Balance</h1>
    12. <p>{{ $filters.currencyUSD(accountBalance) }}</p>
    13. </template>
  • 函数式组件

  • 全局API的变化
    会移动到应用实例上,以下是 Vue2 全局 API 及其相应的实例 API 列表:

2.x 全局 API3.x 实例 API (app)
Vue.configapp.config
Vue.config.productionTip移除 (见下方)
Vue.config.ignoredElementsapp.config.compilerOptions.isCustomElement (见下方)
Vue.componentapp.component
Vue.directiveapp.directive
Vue.mixinapp.mixin
Vue.useapp.use (见下方)
Vue.prototypeapp.config.globalProperties (见下方)
Vue.extend移除 (见下方)

所有其他不全局改变行为的全局 API 现在都是具名导出,文档见全局 API Treeshaking

  • 内联模板(inline-template) https://v3-migration.vuejs.org/zh/breaking-changes/inline-template-attribute.html

  • key属性的使用变化 https://v3-migration.vuejs.org/zh/breaking-changes/key-attribute.html

    • v-if,v-if-else,v-else不再需要key
    • <template v-for> 的 key 应该设置在 <template> 标签上 (而不是设置在它的子节点上)
  • keycode(按钮修饰符)的变化

    1. //vue2
    2. <!-- 键码版本 -->
    3. <input v-on:keyup.13="submit" />
    4. <!-- 别名版本 -->
    5. <input v-on:keyup.enter="submit" />
    6. Vue.config.keyCodes = {
    7. f1: 112
    8. }
    9. <!-- 键码版本 -->
    10. <input v-on:keyup.112="showHelpText" />
    11. <!-- 自定义别名版本 -->
    12. <input v-on:keyup.f1="showHelpText" />
    1. //vue3 直接使用键名,中线连接
    2. <!-- Vue 3 v-on 上使用按键修饰符 -->
    3. <input v-on:keyup.page-down="nextPage">
    4. <!-- 同时匹配 q Q -->
    5. <input v-on:keypress.q="quit">
  • slot的变化,参考 https://v3-migration.vuejs.org/zh/breaking-changes/slots-unification.html
  • v-bind行为变化

    • vue2中单独的属性会覆盖v-bind中的对象属性
      1. <!-- 模板 -->
      2. <div id="red" v-bind="{ id: 'blue' }"></div>
      3. <!-- 结果 -->
      4. <div id="red"></div>
    • vue3中看先后顺序,在后面的覆盖前面的

      1. <!-- 模板 -->
      2. <div id="red" v-bind="{ id: 'blue' }"></div>
      3. <!-- 结果 -->
      4. <div id="blue"></div>
      5. <!-- 模板 -->
      6. <div v-bind="{ id: 'blue' }" id="red"></div>
      7. <!-- 结果 -->
      8. <div id="red"></div>
  • v-model的变化 https://v3-migration.vuejs.org/zh/breaking-changes/v-model.html

  • 使用watch监听数组(Array)的变化 https://v3-migration.vuejs.org/zh/breaking-changes/watch.html

    1. // 不使用deep时,只有整个数组被替换才会触发watch
    2. // 在vue2时,watch数组不需要使用deep,在vue2中,deep只是用在Object上
    3. watch: {
    4. bookList: {
    5. handler(val, oldVal) {
    6. console.log('book list changed')
    7. },
    8. deep: true
    9. },
    10. }
  • nexttick https://cn.vuejs.org/api/general.html#nexttick

    1. //vue2
    2. // 修改数据
    3. vm.msg = 'Hello'
    4. // DOM 还没有更新
    5. Vue.nextTick(function () {
    6. // DOM 更新了
    7. })
    1. // vue3
    2. // 需要引入
    3. // 以传递一个回调函数作为参数,或者 await 返回的 Promise
    4. <script>
    5. import { nextTick } from 'vue'
    6. export default {
    7. data() {
    8. return {
    9. count: 0
    10. }
    11. },
    12. methods: {
    13. async increment() {
    14. this.count++
    15. // DOM 还未更新
    16. console.log(document.getElementById('counter').textContent) // 0
    17. await nextTick()
    18. // DOM 此时已经更新
    19. console.log(document.getElementById('counter').textContent) // 1
    20. }
    21. }
    22. }
    23. </script>
    24. <template>
    25. <button id="counter" @click="increment">{{ count }}</button>
    26. </template>

-

版权声明:本站文章除特别声明外,均采用署名-非商业性使用-禁止演绎 4.0 国际 许可协议,如需转载,请注明出处