Vue2到Vue3过渡指南(快速上手版)

880 阅读3分钟

众所周知,Vue3相对于Vue2来说发生了断崖式地更新,那么作为开发者,我们需要紧跟技术的发展趋势,将新的内容应用于日常的技术开发当中😎。本文简要地总结了作为一个Vue2的开发者,如何快速上手Vue3的开发实践,让Vue3新手不再迷茫👇👇👇

注:本篇当中的代码的<script>片段,统一采用<script setup>写法,和项目代码保持统一,<script setup>是我们写Vue3一定要去了解的内容,建议在阅读本文之前或是之后去浏览一下这方面的小知识,可以直接看本人的另一篇文章->Vue3当中的setup script - 掘金 (juejin.cn)

一、 了解响应式API

在Vue2当中,我们实现响应式数据的方式是将数据定义在data函数当中返回,在Vue3中虽然同样也可以使用这种方式,但是尤大在Vue3当中是对响应式实现的底层原理做出改进的,改用了ES6Proxy来实现,因此建议使用新版当中的ReactiveRef来实现页面内容的响应式。

Vue2写法:

<template>
  <p>{{msg}}</p>
</template><script>
export default {
  data() {
    return {
      msg: 'message',
      data:{
        text:'xxx',
        status: 1
      }
    };
  }
};
</script>

Vue3写法:

<template>
  <p>{{msg}}</p>
</template><script setup lang="ts"> 
export default {
  const msg = ref('message')
  const data = reative({
        text:'xxx',
        status: 1
  })
  msg.value = 'new message'  //通过value属性进行访问
  data.status = 2   //直接访问
};
</script>

ref ——接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value 属性,指向该内部值。

reactive ——接受复杂类型的数据并返回对象的响应式副本。

注意点:

  • 使用reactive定义基本数据类型时,vue会给出了一个警告,reactive更推荐用于对象或数组的数据类型(因为vue在实现reactive方法,会首先判断传入的数据是否为对象,只有对象才会进行数据响应式处理)
  • 使用ref定义数据时,script当中获取值需要通过.value属性访问,在模板中直接使用
  • ref可以定义基本数据类型,也可以定义复杂数据类型,不会报错
  • 二者简单区分就是一个负责基本数据类型、一个负责复杂数据类型,底层响应式实现逻辑不同

这是我们在日常开发当中使用频率最高的两个响应式API,但除了它们,还有**toReftoRefs**、computedwatchwatchEffect... 可以在具体使用的时候,进行了解;官方文档指路 -> v3.cn.vuejs.org/api/basic-r…

二、 方法定义的差异

在之前的版本当中,我们定义逻辑代码的方式是写在methods和各个生命周期当中,而在Vue3当中可以直接进行方法函数的定义,并且对生命周期的方法重新进行了分配。

Vue2写法:

<template>
  <button @click="getMessage">点击</button>
</template><script>
export default {
  ...
  methods {
    getMessage(){
      console.log('this is msg')
    }
  }
};
</script>

Vue3写法:

<template>
  <button @click="getMessage">点击</button>
</template><script setup lang="ts"> 
import { onMounted, onUpdated, onUnmounted } from 'vue' //需要导入const getMessage = () => {
   console.log('this is msg')
 }
 
 onMounted(() => {
   console.log('mounted!')
 })
 onUpdated(() => {
   console.log('updated!')
 })
 onUnmounted(() => {
   console.log('unmounted!')
 })
...
 
</script>

各生命周期对应如下:

beforeCreate -> 使用 setup()

created -> 使用 setup()

beforeMount -> onBeforeMount

mounted -> onMounted

beforeUpdate -> onBeforeUpdate

updated -> onUpdated

beforeDestroy -> onBeforeUnmount

destroyed -> onUnmounted

errorCaptured -> onErrorCaptured

Vue3 当中的父子组件传值

<script setup>中主要采用definePropsdefineEmit两个API来完成

父组件向子组件传递数据

  1. 在子组件标签当中上通过v-bind + 自定义变量名 进行数据绑定,这里是 :info
  2. 子组件defineProps定义接收到的props
  3. props解构出需要的数据

子组件向父组件传递数据

  1. 父组件编写接收函数,例如这里的 clickEven
  2. 在子组件标签上通过"@" + 自定义事件名 绑定该接收函数
  3. defineEmits注册发射事件名
  4. emit(事件名,数据值)

父组件:

<template>
  <div>老父亲
  <!-- 父组件通过变量(这里是info)进行值的绑定 -->
  <!-- 父组件定义clickEven接收子组件的值 -->
  <Child :info="parentMsg"  @clickChild="clickEven" ></Child>
​
  </div>
</template>
 
<script setup lang="ts">
import Child from './Child'const parentMsg = ref('toChild')
​
//父组件接受子组件传值---startconst clickEven=(val)=>{
  console.log(val)
}
//父组件接受子组件传值---end
 
</script>

子组件:

<template>
  <!-- info是父组件传递过来的值 -->
  <div>我是乖儿子拿到了父组件的值是{{info}}</div>
  <!-- clickChild子组件事件 -->
  <button @click="clickChild">点击子组件</button>
</template>
 
<script setup>
import { toRefs, defineProps,defineEmits } from 'vue'//接受父亲的值---start
const props = defineProps({
  //子组件接收父组件传递过来的值
  info: String,
})
//使用父组件传递过来的值
const {info} = toRefs(props)
​
​
//传递给老父亲---start
const emit = defineEmits([clickChild])  //数组形式,可以定义多个//1.包在方法里使用
const clickChild = () => {
  emit('clickChild','toFather')
}
//2.直接使用
emit('clickChild','toFather')
​
 
</script>

对于子组件向父组件传值,还可以使用defineExpose进行属性和方法的暴露,父组件定义ref接收

  1. 父组件中定义一个ref,并绑定在子组件标签上,例如这里的 controlRef
  2. 子组件通过defineExpose()暴露数据或方法
  3. 父组件通过ref获取,例如 controlRef.value.myTag

子组件:

<template>
  <div>
        <h2>乖儿子</h2>
        <p>tag:{{ myTag }}</p>
    </div>
</template>
 
<script setup lang=ts>
import { defineExpose } from "vue";
​
const myTag=ref('小可爱')
const changeTag = () => {
  myTag.value = '大美丽'
}
defineExpose({ myTag, changeTag })
</script>

父组件:

<template>
  <div> 
    <!-- 在组件上绑定ref -->
    <Child ref="controlRef"></Child>
 </div>
</template>
 
<script setup lang=ts>
import Child from './Child'
const controlRef = ref()
​
const data = controlRef.value.myTag//使用方法
controlRef.changeTag()
​
</script>

除以上两种方法之外,也可以使用provideinject ,支持多层父子级嵌套,深层套娃时使用效果佳,如下:

具体的API介绍,可以看官网->v3.cn.vuejs.org/guide/compo…

//Father.vue
<template>
  <Child />
</template>
<script setup>
import Child from '../components/HelloWorld.vue'
import { reactive, provide } from 'vue'const state=reactive({
  title:'你好'
})
//provide
provide('provideToChild', {
    state,
    changeTitle: (FromChildParams) => {
      state.title=FromChildParams
    }
  })
// provide('provideToChild',state )
</script>
​
//child.vue
​
<template>
  我是子组件 {{injectFromParent}}
</template>
<script setup>
import {inject} from 'vue'
//注入
const injectFromParent= inject('provideToChild');
injectFromParent.changeTitle('MontherFucker');
​
</script>

小结

通过了解以上Vue2和Vue3的一些写法上基础性差异,就可以去动手写一个vue3的页面了,实践出真知!再根据具体的需求来查看再Vue3当中应如何去实现(本人亲测有效);

But 这些只是我们在写代码的时候,能感受出来的很表面的差异,具体Vue3内部如何实现,为什么可以这样使用这些API,都是可以进一步去探索的。同时,这些用法差异仅仅冰山一角,本文也只是编写了一小部分,目的是让读者看完之后可以简单上手,更多的差异还等待着大家亲自去探索噢👸~