vue3相比vue2有哪些变化?


API和数据响应式的变化

去除构造函数

在vue2中,当一个页面需要多个vue应用时,在需要插件的场景下,会导致多个应用都挂载了相同的插件,因为插件的注册是在new vue之前,即挂载在vue的原型上。

Vue.use(XXX)
Vue.mixin(XXX)

new Vue({
    
    }).$mount('#app1')
new Vue({
    
    }).$mount('#app2')

在vue3中,去除了构造函数,转而使用createApp的方法创建vue应用,可以链式调用。

import {
    
     createApp } from 'vue'
import App from './App.vue'

createApp(App).use(XXX).mount('#app1')
createApp(App).mount('#app2')

vue3去除构造函数大概是以下几点原因:

  1. 构造函数的形式不利于隔离不同的应用。调用构造函数的静态方法会对所有vue应用生效。
  2. 构造函数的形式不利于tree shaking,vue2的构造函数集成了太多功能,vue3把这些功能使用普通的函数导出,这样有利于tree shaking优化打包体积。
  3. vue2 在设计上没有把组件实例和vue应用这两个概念区分开,在vue2中,通过new Vue创建的对象,既是一个vue应用,同时又是一个特殊的组件。vue3中,把这两个概念区分开来,通过createApp创建的对象,是一个vue应用,它内部提供的方法是针对整个应用,而不再是一个特殊的组件。(vue2中,new Vue之后的对象有着很多组件身上的方法)

组件实例中的API

vue3的组件实例是一个Proxy,它有着和vue2一样的大多数方法。只是vue3的组件实例身上的方法会比vue2少很多,因为是通过Proxy代理,所以不该被开发者访问的方法,Proxy并不会返回,所以vue3在成员方法上会比vue2少很多。

<script>
export default {
    
    
	created(){
    
    
		console.log(this)//组件实例是一个Proxy
	}
}
</script>

响应式的变化

vue2和vue3都是在相同的生命周期(beforeCreate之后、created之前)完成数据的响应式。

实现上,vue2使用Object.defineProperty完成数据的响应式,在对象里使用递归,当树的层级较深时,需要耗费一定的性能,而且在某些情况下并不能做到对某些数据进行响应式监听,所以需要 s e t 、 set、 setdelete方法处理。

而vue3使用Proxy代理数据,无需遍历对象,直接new Proxy即可完成数据的响应式处理。而且并不会存在新增数据删除数据监听不到的情况,所以vue3并没有$set、$delete的方法,新增数据、删除数据、索引访问等均可触发响应式处理。

生命周期

声明周期图片

Vue3新增

vue3新增了Reactivity API 和Composition API,setup语法糖等。
setup使得我们编写代码更加灵活。

Reactivity API
Composition API


模板中的变化

v-model与.sync修饰符

vue2双向数据绑定的方法有两种,v-model和.sync。

在vue3中,去掉了.sync修饰符,在vue3使用.sync会出现以下警告(’.sync’ modifier on ‘v-bind’ directive is deprecated. Use ‘v-model:propName’ instead.),只有v-model这个方法可以进行双向绑定。

vue3对v-model做了以下修改:

  1. 当对自定义组件使用v-model时,绑定的属性名由原来的value变为modelValue,事件名由原来的input变为update:modelValue。
//vue2
<my-component :value="myValue" @input="handleInput" />
//vue2-简写
<my-component v-model="myValue" />

//vue3
<my-component :modelValue="myValue" @update:modelValue="handleModel" />
//vue3-简写
<my-compoonent v-model="myValue" />
  1. 去掉了.sync修饰符,它原本的功能由v-model参数代替。
//vue2
<my-component :value="myValue" @update:value="myValue = $event" />
//vue2-简写
<my-component :value.sync="myValue" />

//vue3
<my-component :value="myValue" @update:value="myValue = $event" />
//vue3-简写
<my-compoonent v-model:value="myValue" />
  1. vue3里,mode配置被移除
  2. vue3相比vue2,新增了自定义v-model修饰符
//父组件
<Comp v-model.cap="data1" v-model:text.cap="data2" />

//子组件
//自定义的v-model修饰符会放在props的[propName]Modifiers里,其数据是一个对象,包含了传进来的修饰符
props:{
    
    
	textModifiers:{
    
    
		default:()=>{
    
    }
	}
}

v-for和v-if

vue2中v-for优先级高于v-if,虽然vue2规范中不建议v-for和v-if同写一行,因为在循环中+判断这样会带来性能问题。

vue3中v-if优先级高于v-for,因为vue3觉得vue2既然不推荐v-for和v-if同行,那设置优先级本身没有什么意义。

key

  1. 当使用<template>进行v-for时,vue3需要把key放在<template>,而不是把key放在子元素中。(vue2是把key放在子元素)。
  2. 当使用v-if、v-else-if、v-else不再需要使用key,因为vue3会自动给予每个分支一个唯一的key。

Fragment

vue3允许组件出现多个根节点,同react的Fragment会生成虚拟的根节点。


组件的变化

异步组件

defineAsyncComponent可以创建一个只有在需要时才会加载的异步组件。

import {
    
     defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent({
    
    
  // 工厂函数
  loader: () => import('./Foo.vue'),
  // 加载异步组件时要使用的组件
  loadingComponent: LoadingComponent,
  // 加载失败时要使用的组件
  errorComponent: ErrorComponent,
  // 在显示 loadingComponent 之前的延迟 | 默认值:200(单位 ms)
  delay: 200,
  // 如果提供了 timeout ,并且加载组件的时间超过了设定值,将显示错误组件
  // 默认值:Infinity(即永不超时,单位 ms)
  timeout: 3000,
  // 定义组件是否可挂起 | 默认值:true
  suspensible: false,
  /**
   *
   * @param {*} error 错误信息对象
   * @param {*} retry 一个函数,用于指示当 promise 加载器 reject 时,加载器是否应该重试
   * @param {*} fail  一个函数,指示加载程序结束退出
   * @param {*} attempts 允许的最大重试次数
   */
  onError(error, retry, fail, attempts) {
    
    
    if (error.message.match(/fetch/) && attempts <= 3) {
    
    
      // 请求发生错误时重试,最多可尝试 3 次
      retry()
    } else {
    
    
      // 注意,retry/fail 就像 promise 的 resolve/reject 一样:
      // 必须调用其中一个才能继续错误处理。
      fail()
    }
  }
})

试验性的Suspense,Suspense 是一个试验性的新特性,其 API 可能随时会发生变动。

该 <suspense> 组件提供了另一个方案,允许将等待过程提升到组件树中处理,而不是在单个组件中。

<suspense> 组件有两个插槽。它们都只接收一个直接子节点。default 插槽里的节点会尽可能展示出来。如果不能,则展示 fallback 插槽里的节点。

<template>
  <suspense>
    <template #default>
      <todo-list />
    </template>
    <template #fallback>
      <div>
        Loading...
      </div>
    </template>
  </suspense>
</template>

<script>
export default {
    
    
  components: {
    
    
    TodoList: defineAsyncComponent(() => import('./TodoList.vue'))
  }
}
</script>

可自行更改组件结构

<teleport>可以将组件元素嵌套在另一个元素内部,以构建一个组成应用程序 UI 的树。

有时组件模板的一部分逻辑上属于该组件,而从技术角度来看,最好将模板的这一部分移动到 DOM 中 Vue app 之外的其他位置

以蒙层功能为例,我们可以在组件内部将其插入到body里。

app.component('modal-button', {
    
    
  template: `
    <button @click="modalOpen = true">
        Open full screen modal! (With teleport!)
    </button>

    <teleport to="body">
      <div v-if="modalOpen" class="modal">
        <div>
          I'm a teleported modal! 
          (My parent is "body")
          <button @click="modalOpen = false">
            Close
          </button>
        </div>
      </div>
    </teleport>
  `,
  data() {
    
    
    return {
    
     
      modalOpen: false
    }
  }
})

猜你喜欢

转载自blog.csdn.net/Mr_RedStar/article/details/123537033